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

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
14 // static 17 // static
15 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( 18 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
16 VideoFrame::Format format, 19 VideoFrame::Format format,
17 size_t width, 20 size_t width,
18 size_t height, 21 size_t height,
22 size_t alignment,
19 base::TimeDelta timestamp, 23 base::TimeDelta timestamp,
20 base::TimeDelta duration) { 24 base::TimeDelta duration) {
21 DCHECK(IsValidConfig(format, width, height)); 25 DCHECK(IsValidConfig(format, width, height, alignment));
22 scoped_refptr<VideoFrame> frame(new VideoFrame( 26 scoped_refptr<VideoFrame> frame(new VideoFrame(
23 format, width, height, timestamp, duration)); 27 format, width, height, timestamp, duration));
24 switch (format) { 28 switch (format) {
25 case VideoFrame::RGB32: 29 case VideoFrame::RGB32:
26 frame->AllocateRGB(4u); 30 frame->AllocateRGB(4u, alignment);
scherkus (not reviewing) 2012/06/14 02:21:33 fix indent here
27 break; 31 break;
28 case VideoFrame::YV12: 32 case VideoFrame::YV12:
29 case VideoFrame::YV16: 33 case VideoFrame::YV16:
30 frame->AllocateYUV(); 34 frame->AllocateYUV(alignment);
scherkus (not reviewing) 2012/06/14 02:21:33 fix indent here
31 break; 35 break;
32 default: 36 default:
33 LOG(FATAL) << "Unsupported frame format: " << format; 37 LOG(FATAL) << "Unsupported frame format: " << format;
34 } 38 }
35 return frame; 39 return frame;
36 } 40 }
37 41
38 // static 42 // static
39 bool VideoFrame::IsValidConfig( 43 bool VideoFrame::IsValidConfig(
40 VideoFrame::Format format, 44 VideoFrame::Format format,
41 size_t width, 45 size_t width,
42 size_t height) { 46 size_t height,
47 size_t alignment) {
43 48
44 return (format != VideoFrame::INVALID && 49 return (format != VideoFrame::INVALID &&
45 width > 0 && height > 0 && 50 width > 0 && height > 0 &&
46 width <= limits::kMaxDimension && height <= limits::kMaxDimension && 51 width <= limits::kMaxDimension && height <= limits::kMaxDimension &&
47 width * height <= limits::kMaxCanvas); 52 width * height <= limits::kMaxCanvas && alignment > 0);
scherkus (not reviewing) 2012/06/14 02:21:33 shouldn't alignment be checked for power of 2? ch
48 } 53 }
49 54
50 // static 55 // static
51 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( 56 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
52 uint32 texture_id, 57 uint32 texture_id,
53 uint32 texture_target, 58 uint32 texture_target,
54 size_t width, 59 size_t width,
55 size_t height, 60 size_t height,
56 base::TimeDelta timestamp, 61 base::TimeDelta timestamp,
57 base::TimeDelta duration, 62 base::TimeDelta duration,
(...skipping 13 matching lines...) Expand all
71 } 76 }
72 77
73 // static 78 // static
74 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) { 79 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) {
75 DCHECK_GT(width, 0); 80 DCHECK_GT(width, 0);
76 DCHECK_GT(height, 0); 81 DCHECK_GT(height, 0);
77 82
78 // Create our frame. 83 // Create our frame.
79 const base::TimeDelta kZero; 84 const base::TimeDelta kZero;
80 scoped_refptr<VideoFrame> frame = 85 scoped_refptr<VideoFrame> frame =
81 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero, kZero); 86 VideoFrame::CreateFrame(VideoFrame::YV12, width, height,
scherkus (not reviewing) 2012/06/14 02:21:33 revert change here
87 kZero, kZero);
82 88
83 // Now set the data to YUV(0,128,128). 89 // Now set the data to YUV(0,128,128).
84 const uint8 kBlackY = 0x00; 90 const uint8 kBlackY = 0x00;
85 const uint8 kBlackUV = 0x80; 91 const uint8 kBlackUV = 0x80;
86 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); 92 FillYUV(frame, kBlackY, kBlackUV, kBlackUV);
87 return frame; 93 return frame;
88 } 94 }
89 95
90 static inline size_t RoundUp(size_t value, size_t alignment) { 96 static inline size_t RoundUp(size_t value, size_t alignment) {
91 // Check that |alignment| is a power of 2. 97 // Check that |alignment| is a power of 2.
92 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); 98 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
93 return ((value + (alignment - 1)) & ~(alignment-1)); 99 return ((value + (alignment - 1)) & ~(alignment-1));
94 } 100 }
95 101
96 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { 102 static inline size_t Max(size_t a, size_t b) {
scherkus (not reviewing) 2012/06/14 02:21:33 use std::max() instead?
103 return a > b ? a : b;
104 }
105
106 void VideoFrame::AllocateRGB(size_t bytes_per_pixel, size_t alignment) {
97 // Round up to align at a 64-bit (8 byte) boundary for each row. This 107 // Round up to align at a 64-bit (8 byte) boundary for each row. This
98 // is sufficient for MMX reads (movq). 108 // is sufficient for MMX reads (movq).
99 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8); 109 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, Max(alignment, 8u));
110 size_t aligned_height = RoundUp(height_, alignment);
100 strides_[VideoFrame::kRGBPlane] = bytes_per_row; 111 strides_[VideoFrame::kRGBPlane] = bytes_per_row;
101 data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_]; 112 #if !defined(OS_ANDROID)
113 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
scherkus (not reviewing) 2012/06/14 02:21:33 s/TODO/TODO(dalecurtis):/
114 // repeated in every single user of aligned data.
115 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8 *>(
scherkus (not reviewing) 2012/06/14 02:21:33 pointers go w/ types good: uint8* var bad: uint8
116 av_malloc(bytes_per_row * aligned_height));
scherkus (not reviewing) 2012/06/14 02:21:33 4-space indent
117 #else
118 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height];
119 #endif
102 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); 120 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
103 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); 121 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
104 } 122 }
105 123
106 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert. 124 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert.
107 125
108 void VideoFrame::AllocateYUV() { 126 void VideoFrame::AllocateYUV(size_t alignment) {
109 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); 127 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16);
110 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and 128 // 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 129 // 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 130 // 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 131 // 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. 132 // 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 133 // 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 134 // 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 135 // values of the final row, but assumes that the last row of U & V applies to
118 // a full two rows of Y. 136 // a full two rows of Y.
scherkus (not reviewing) 2012/06/14 02:21:33 comment needs updating to say this does a minimum
119 size_t y_height = rows(VideoFrame::kYPlane); 137 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
120 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 4); 138 Max(alignment, 4u));
121 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 4); 139 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
122 size_t uv_height = rows(VideoFrame::kUPlane); 140 Max(alignment, 4u));
141 size_t y_height = RoundUp(height_, Max(alignment, 2u));
142 size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height;
123 size_t y_bytes = y_height * y_stride; 143 size_t y_bytes = y_height * y_stride;
124 size_t uv_bytes = uv_height * uv_stride; 144 size_t uv_bytes = uv_height * uv_stride;
125 145
126 uint8* data = new uint8[y_bytes + (uv_bytes * 2) + kFramePadBytes]; 146 #if !defined(OS_ANDROID)
147 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
scherkus (not reviewing) 2012/06/14 02:21:33 ditto
148 // repeated in every single user of aligned data.
149 uint8* data = reinterpret_cast<uint8 *>(
scherkus (not reviewing) 2012/06/14 02:21:33 ditto for pointers
150 av_malloc(y_bytes + (uv_bytes * 2) + kFramePadBytes));
151 #else
152 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2) + kFramePadBytes];
153 #endif
127 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);
128 data_[VideoFrame::kYPlane] = data; 155 data_[VideoFrame::kYPlane] = data;
129 data_[VideoFrame::kUPlane] = data + y_bytes; 156 data_[VideoFrame::kUPlane] = data + y_bytes;
130 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; 157 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
131 strides_[VideoFrame::kYPlane] = y_stride; 158 strides_[VideoFrame::kYPlane] = y_stride;
132 strides_[VideoFrame::kUPlane] = uv_stride; 159 strides_[VideoFrame::kUPlane] = uv_stride;
133 strides_[VideoFrame::kVPlane] = uv_stride; 160 strides_[VideoFrame::kVPlane] = uv_stride;
134 } 161 }
135 162
136 VideoFrame::VideoFrame(VideoFrame::Format format, 163 VideoFrame::VideoFrame(VideoFrame::Format format,
(...skipping 14 matching lines...) Expand all
151 178
152 VideoFrame::~VideoFrame() { 179 VideoFrame::~VideoFrame() {
153 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { 180 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) {
154 texture_no_longer_needed_.Run(); 181 texture_no_longer_needed_.Run();
155 texture_no_longer_needed_.Reset(); 182 texture_no_longer_needed_.Reset();
156 } 183 }
157 184
158 // In multi-plane allocations, only a single block of memory is allocated 185 // 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 186 // on the heap, and other |data| pointers point inside the same, single block
160 // so just delete index 0. 187 // so just delete index 0.
161 delete[] data_[0]; 188 if (data_[0]) {
189 #if !defined(OS_ANDROID)
190 av_free(data_[0]);
191 #else
192 delete[] data_[0];
193 #endif
194 }
162 } 195 }
163 196
164 bool VideoFrame::IsValidPlane(size_t plane) const { 197 bool VideoFrame::IsValidPlane(size_t plane) const {
165 switch (format_) { 198 switch (format_) {
166 case RGB32: 199 case RGB32:
167 return plane == kRGBPlane; 200 return plane == kRGBPlane;
168 201
169 case YV12: 202 case YV12:
170 case YV16: 203 case YV16:
171 return plane == kYPlane || plane == kUPlane || plane == kVPlane; 204 return plane == kYPlane || plane == kUPlane || plane == kVPlane;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 break; 290 break;
258 for(int row = 0; row < rows(plane); row++) { 291 for(int row = 0; row < rows(plane); row++) {
259 base::MD5Update(context, base::StringPiece( 292 base::MD5Update(context, base::StringPiece(
260 reinterpret_cast<char*>(data(plane) + stride(plane) * row), 293 reinterpret_cast<char*>(data(plane) + stride(plane) * row),
261 row_bytes(plane))); 294 row_bytes(plane)));
262 } 295 }
263 } 296 }
264 } 297 }
265 298
266 } // namespace media 299 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698