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

Side by Side Diff: media/video/gpu_memory_buffer_video_frame_pool.cc

Issue 1306693002: media: Convert I420 VideoFrame to UYVY GpuMemoryBuffer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address reviewers' comments. Created 5 years, 4 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/video/gpu_memory_buffer_video_frame_pool.h" 5 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
6 6
7 #include <GLES2/gl2.h> 7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h> 8 #include <GLES2/gl2ext.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <list> 11 #include <list>
12 #include <utility> 12 #include <utility>
13 13
14 #include "base/barrier_closure.h" 14 #include "base/barrier_closure.h"
15 #include "base/bind.h" 15 #include "base/bind.h"
16 #include "base/containers/stack_container.h" 16 #include "base/containers/stack_container.h"
17 #include "base/location.h" 17 #include "base/location.h"
18 #include "base/memory/linked_ptr.h" 18 #include "base/memory/linked_ptr.h"
19 #include "base/trace_event/trace_event.h" 19 #include "base/trace_event/trace_event.h"
20 #include "gpu/command_buffer/client/gles2_interface.h" 20 #include "gpu/command_buffer/client/gles2_interface.h"
21 #include "media/renderers/gpu_video_accelerator_factories.h" 21 #include "media/renderers/gpu_video_accelerator_factories.h"
22 #include "third_party/libyuv/include/libyuv.h"
23 #include "ui/gfx/buffer_format_util.h"
22 24
23 namespace media { 25 namespace media {
24 26
25 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames. 27 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames.
26 class GpuMemoryBufferVideoFramePool::PoolImpl 28 class GpuMemoryBufferVideoFramePool::PoolImpl
27 : public base::RefCountedThreadSafe< 29 : public base::RefCountedThreadSafe<
28 GpuMemoryBufferVideoFramePool::PoolImpl> { 30 GpuMemoryBufferVideoFramePool::PoolImpl> {
29 public: 31 public:
30 // |media_task_runner| is the media task runner associated with the 32 // |media_task_runner| is the media task runner associated with the
31 // GL context provided by |gpu_factories| 33 // GL context provided by |gpu_factories|
32 // |worker_task_runner| is a task runner used to asynchronously copy 34 // |worker_task_runner| is a task runner used to asynchronously copy
33 // video frame's planes. 35 // video frame's planes.
34 // |gpu_factories| is an interface to GPU related operation and can be 36 // |gpu_factories| is an interface to GPU related operation and can be
35 // null if a GL context is not available. 37 // null if a GL context is not available.
36 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 38 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
37 const scoped_refptr<base::TaskRunner>& worker_task_runner, 39 const scoped_refptr<base::TaskRunner>& worker_task_runner,
38 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) 40 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories)
39 : media_task_runner_(media_task_runner), 41 : media_task_runner_(media_task_runner),
40 worker_task_runner_(worker_task_runner), 42 worker_task_runner_(worker_task_runner),
41 gpu_factories_(gpu_factories), 43 gpu_factories_(gpu_factories),
42 texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget() 44 texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget()
43 : GL_TEXTURE_2D) { 45 : GL_TEXTURE_2D),
46 output_format_(gpu_factories ? gpu_factories->VideoFrameOutputFormat()
47 : PIXEL_FORMAT_I420) {
44 DCHECK(media_task_runner_); 48 DCHECK(media_task_runner_);
45 DCHECK(worker_task_runner_); 49 DCHECK(worker_task_runner_);
46 } 50 }
47 51
48 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame 52 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame
49 // backed by native textures if possible. 53 // backed by native textures if possible.
50 // The data contained in video_frame is copied into the returned frame 54 // The data contained in video_frame is copied into the returned frame
51 // asynchronously posting tasks to |worker_task_runner_|, while 55 // asynchronously posting tasks to |worker_task_runner_|, while
52 // |frame_ready_cb| will be called on |media_task_runner_| once all the data 56 // |frame_ready_cb| will be called on |media_task_runner_| once all the data
53 // has been copied. 57 // has been copied.
54 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame, 58 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame,
55 const FrameReadyCB& cb); 59 const FrameReadyCB& cb);
56 60
57 private: 61 private:
58 friend class base::RefCountedThreadSafe< 62 friend class base::RefCountedThreadSafe<
59 GpuMemoryBufferVideoFramePool::PoolImpl>; 63 GpuMemoryBufferVideoFramePool::PoolImpl>;
60 ~PoolImpl(); 64 ~PoolImpl();
61 65
62 // Resource to represent a plane. 66 // Resource to represent a plane.
63 struct PlaneResource { 67 struct PlaneResource {
64 gfx::Size size; 68 gfx::Size size;
65 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; 69 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
66 unsigned texture_id = 0u; 70 unsigned texture_id = 0u;
67 unsigned image_id = 0u; 71 unsigned image_id = 0u;
68 gpu::Mailbox mailbox; 72 gpu::Mailbox mailbox;
69 }; 73 };
70 74
71 // All the resources needed to compose a frame. 75 // All the resources needed to compose a frame.
72 struct FrameResources { 76 struct FrameResources {
73 FrameResources(VideoPixelFormat format, const gfx::Size& size) 77 explicit FrameResources(const gfx::Size& size) : size(size) {}
74 : format(format), size(size) {}
75 bool in_use = true; 78 bool in_use = true;
76 VideoPixelFormat format;
77 gfx::Size size; 79 gfx::Size size;
78 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; 80 PlaneResource plane_resources[VideoFrame::kMaxPlanes];
79 }; 81 };
80 82
81 // Copy |video_frame| data into |frame_resouces| 83 // Copy |video_frame| data into |frame_resouces|
82 // and calls |done| when done. 84 // and calls |done| when done.
83 void CopyVideoFrameToGpuMemoryBuffers( 85 void CopyVideoFrameToGpuMemoryBuffers(
84 const scoped_refptr<VideoFrame>& video_frame, 86 const scoped_refptr<VideoFrame>& video_frame,
85 FrameResources* frame_resources, 87 FrameResources* frame_resources,
86 const FrameReadyCB& frame_ready_cb); 88 const FrameReadyCB& frame_ready_cb);
87 89
88 // Called when all the data has been copied. 90 // Called when all the data has been copied.
89 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, 91 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame,
90 FrameResources* frame_resources, 92 FrameResources* frame_resources,
91 const FrameReadyCB& frame_ready_cb); 93 const FrameReadyCB& frame_ready_cb);
92 94
93 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new 95 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new
94 // VideoFrame. 96 // VideoFrame.
95 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also 97 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also
96 // be run. 98 // be run.
97 void BindAndCreateMailboxesHardwareFrameResources( 99 void BindAndCreateMailboxesHardwareFrameResources(
98 const scoped_refptr<VideoFrame>& video_frame, 100 const scoped_refptr<VideoFrame>& video_frame,
99 FrameResources* frame_resources, 101 FrameResources* frame_resources,
100 const FrameReadyCB& frame_ready_cb); 102 const FrameReadyCB& frame_ready_cb);
101 103
102 // Return true if |resources| can be used to represent a frame for 104 // Return true if |resources| can be used to represent a frame for
103 // specific |format| and |size|. 105 // specific |format| and |size|.
104 static bool AreFrameResourcesCompatible(const FrameResources* resources, 106 static bool AreFrameResourcesCompatible(const FrameResources* resources,
105 const gfx::Size& size, 107 const gfx::Size& size) {
106 VideoPixelFormat format) { 108 return size == resources->size;
107 return size == resources->size && format == resources->format;
108 } 109 }
109 110
110 // Get the resources needed for a frame out of the pool, or create them if 111 // Get the resources needed for a frame out of the pool, or create them if
111 // necessary. 112 // necessary.
112 // This also drops the LRU resources that can't be reuse for this frame. 113 // This also drops the LRU resources that can't be reuse for this frame.
113 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, 114 FrameResources* GetOrCreateFrameResources(const gfx::Size& size,
114 VideoPixelFormat format); 115 VideoPixelFormat format);
115 116
116 // Callback called when a VideoFrame generated with GetFrameResources is no 117 // Callback called when a VideoFrame generated with GetFrameResources is no
117 // longer referenced. 118 // longer referenced.
(...skipping 16 matching lines...) Expand all
134 // Task runner used to asynchronously copy planes. 135 // Task runner used to asynchronously copy planes.
135 scoped_refptr<base::TaskRunner> worker_task_runner_; 136 scoped_refptr<base::TaskRunner> worker_task_runner_;
136 137
137 // Interface to GPU related operations. 138 // Interface to GPU related operations.
138 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; 139 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_;
139 140
140 // Pool of resources. 141 // Pool of resources.
141 std::list<FrameResources*> resources_pool_; 142 std::list<FrameResources*> resources_pool_;
142 143
143 const unsigned texture_target_; 144 const unsigned texture_target_;
145 const VideoPixelFormat output_format_;
146
144 DISALLOW_COPY_AND_ASSIGN(PoolImpl); 147 DISALLOW_COPY_AND_ASSIGN(PoolImpl);
145 }; 148 };
146 149
147 namespace { 150 namespace {
148 151
149 // VideoFrame copies to GpuMemoryBuffers will be split in |kBytesPerCopyTarget| 152 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the
150 // bytes copies and run in parallel. 153 // output size is |kBytesPerCopyTarget| bytes and run in parallel.
151 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB 154 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB
152 155
153 void CopyRowsToBuffer(int first_row, 156 // Return the GpuMemoryBuffer format to use for a specific VideoPixelFormat
154 int rows, 157 // and plane.
155 int bytes_per_row, 158 gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) {
156 const uint8* source, 159 switch (format) {
157 int source_stride, 160 case PIXEL_FORMAT_I420:
158 uint8* output, 161 DCHECK_LE(plane, 2u);
159 int dest_stride, 162 return gfx::BufferFormat::R_8;
160 const base::Closure& done) { 163 case PIXEL_FORMAT_UYVY:
161 TRACE_EVENT2("media", "CopyRowsToBuffer", "bytes_per_row", bytes_per_row, 164 DCHECK_EQ(0u, plane);
165 return gfx::BufferFormat::UYVY_422;
166 default:
167 NOTREACHED();
168 return gfx::BufferFormat::BGRA_8888;
169 }
170 }
171
172 unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) {
173 switch (format) {
174 case PIXEL_FORMAT_I420:
175 DCHECK_LE(plane, 2u);
176 return GL_R8_EXT;
177 case PIXEL_FORMAT_UYVY:
178 DCHECK_EQ(0u, plane);
179 return GL_RGB;
180 default:
181 NOTREACHED();
182 return 0;
183 }
184 }
185
186 void CopyRowsToI420Buffer(int first_row,
187 int rows,
188 int bytes_per_row,
189 const uint8* source,
190 int source_stride,
191 uint8* output,
192 int dest_stride,
193 const base::Closure& done) {
194 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row,
162 "rows", rows); 195 "rows", rows);
163 DCHECK_NE(dest_stride, 0); 196 DCHECK_NE(dest_stride, 0);
164 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); 197 DCHECK_LE(bytes_per_row, std::abs(dest_stride));
165 DCHECK_LE(bytes_per_row, source_stride); 198 DCHECK_LE(bytes_per_row, source_stride);
166 for (int row = first_row; row < first_row + rows; ++row) { 199 for (int row = first_row; row < first_row + rows; ++row) {
167 memcpy(output + dest_stride * row, source + source_stride * row, 200 memcpy(output + dest_stride * row, source + source_stride * row,
168 bytes_per_row); 201 bytes_per_row);
169 } 202 }
170 done.Run(); 203 done.Run();
171 } 204 }
172 205
206 void CopyRowsToUYVYBuffer(int first_row,
207 int rows,
208 int width,
209 const scoped_refptr<VideoFrame>& source_frame,
210 uint8* output,
211 int dest_stride,
212 const base::Closure& done) {
213 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2,
214 "rows", rows);
215 DCHECK_NE(dest_stride, 0);
216 DCHECK_LE(width, std::abs(dest_stride / 2));
217 DCHECK_EQ(0, first_row % 2);
218 libyuv::I420ToUYVY(
219 source_frame->data(VideoFrame::kYPlane) +
220 first_row * source_frame->stride(VideoFrame::kYPlane),
221 source_frame->stride(VideoFrame::kYPlane),
222 source_frame->data(VideoFrame::kUPlane) +
223 first_row / 2 * source_frame->stride(VideoFrame::kUPlane),
224 source_frame->stride(VideoFrame::kUPlane),
225 source_frame->data(VideoFrame::kVPlane) +
226 first_row / 2 * source_frame->stride(VideoFrame::kVPlane),
227 source_frame->stride(VideoFrame::kVPlane),
228 output + first_row * dest_stride, dest_stride, width, rows);
229 done.Run();
230 }
231
173 } // unnamed namespace 232 } // unnamed namespace
174 233
175 // Creates a VideoFrame backed by native textures starting from a software 234 // Creates a VideoFrame backed by native textures starting from a software
176 // VideoFrame. 235 // VideoFrame.
177 // The data contained in |video_frame| is copied into the VideoFrame passed to 236 // The data contained in |video_frame| is copied into the VideoFrame passed to
178 // |frame_ready_cb|. 237 // |frame_ready_cb|.
179 // This has to be called on the thread where |media_task_runner_| is current. 238 // This has to be called on the thread where |media_task_runner_| is current.
180 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( 239 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
181 const scoped_refptr<VideoFrame>& video_frame, 240 const scoped_refptr<VideoFrame>& video_frame,
182 const FrameReadyCB& frame_ready_cb) { 241 const FrameReadyCB& frame_ready_cb) {
183 DCHECK(media_task_runner_->BelongsToCurrentThread()); 242 DCHECK(media_task_runner_->BelongsToCurrentThread());
184 if (!gpu_factories_ || !gpu_factories_->IsTextureRGSupported()) { 243 if (!gpu_factories_ || (output_format_ == PIXEL_FORMAT_I420 &&
244 !gpu_factories_->IsTextureRGSupported())) {
185 frame_ready_cb.Run(video_frame); 245 frame_ready_cb.Run(video_frame);
186 return; 246 return;
187 } 247 }
188 switch (video_frame->format()) { 248 switch (video_frame->format()) {
189 // Supported cases. 249 // Supported cases.
190 case PIXEL_FORMAT_YV12: 250 case PIXEL_FORMAT_YV12:
191 case PIXEL_FORMAT_I420: 251 case PIXEL_FORMAT_I420:
192 break; 252 break;
193 // Unsupported cases. 253 // Unsupported cases.
194 case PIXEL_FORMAT_YV12A: 254 case PIXEL_FORMAT_YV12A:
195 case PIXEL_FORMAT_YV16: 255 case PIXEL_FORMAT_YV16:
196 case PIXEL_FORMAT_YV24: 256 case PIXEL_FORMAT_YV24:
197 case PIXEL_FORMAT_NV12: 257 case PIXEL_FORMAT_NV12:
198 case PIXEL_FORMAT_ARGB: 258 case PIXEL_FORMAT_ARGB:
199 case PIXEL_FORMAT_XRGB: 259 case PIXEL_FORMAT_XRGB:
200 case PIXEL_FORMAT_UYVY: 260 case PIXEL_FORMAT_UYVY:
201 case PIXEL_FORMAT_UNKNOWN: 261 case PIXEL_FORMAT_UNKNOWN:
202 frame_ready_cb.Run(video_frame); 262 frame_ready_cb.Run(video_frame);
203 return; 263 return;
204 } 264 }
205 265
206 VideoPixelFormat format = video_frame->format();
207 DCHECK(video_frame->visible_rect().origin().IsOrigin()); 266 DCHECK(video_frame->visible_rect().origin().IsOrigin());
208 const gfx::Size size = video_frame->visible_rect().size(); 267 const gfx::Size size = video_frame->visible_rect().size();
209 268
210 // Acquire resources. Incompatible ones will be dropped from the pool. 269 // Acquire resources. Incompatible ones will be dropped from the pool.
211 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); 270 FrameResources* frame_resources =
271 GetOrCreateFrameResources(size, output_format_);
212 if (!frame_resources) { 272 if (!frame_resources) {
213 frame_ready_cb.Run(video_frame); 273 frame_ready_cb.Run(video_frame);
214 return; 274 return;
215 } 275 }
216 276
217 worker_task_runner_->PostTask( 277 worker_task_runner_->PostTask(
218 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, 278 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this,
219 video_frame, frame_resources, frame_ready_cb)); 279 video_frame, frame_resources, frame_ready_cb));
220 } 280 }
221 281
222 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( 282 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(
223 const scoped_refptr<VideoFrame>& video_frame, 283 const scoped_refptr<VideoFrame>& video_frame,
224 FrameResources* frame_resources, 284 FrameResources* frame_resources,
225 const FrameReadyCB& frame_ready_cb) { 285 const FrameReadyCB& frame_ready_cb) {
226 const VideoPixelFormat format = video_frame->format(); 286 const size_t planes = VideoFrame::NumPlanes(output_format_);
227 const size_t planes = VideoFrame::NumPlanes(format);
228 for (size_t i = 0; i < planes; ++i) { 287 for (size_t i = 0; i < planes; ++i) {
229 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); 288 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap();
230 } 289 }
231 290
232 media_task_runner_->PostTask( 291 media_task_runner_->PostTask(
233 FROM_HERE, 292 FROM_HERE,
234 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this, 293 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this,
235 video_frame, frame_resources, frame_ready_cb)); 294 video_frame, frame_resources, frame_ready_cb));
236 } 295 }
237 296
238 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks 297 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks
239 // that will be synchronized by a barrier. 298 // that will be synchronized by a barrier.
240 // After the barrier is passed OnCopiesDone will be called. 299 // After the barrier is passed OnCopiesDone will be called.
241 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( 300 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
242 const scoped_refptr<VideoFrame>& video_frame, 301 const scoped_refptr<VideoFrame>& video_frame,
243 FrameResources* frame_resources, 302 FrameResources* frame_resources,
244 const FrameReadyCB& frame_ready_cb) { 303 const FrameReadyCB& frame_ready_cb) {
245 const VideoPixelFormat format = video_frame->format(); 304 // Compute the number of tasks to post and create the barrier.
246 const size_t planes = VideoFrame::NumPlanes(format); 305 const size_t dest_planes = VideoFrame::NumPlanes(output_format_);
247 gfx::Size size = video_frame->visible_rect().size(); 306 gfx::Size size = video_frame->visible_rect().size();
248 size_t copies = 0; 307 size_t copies = 0;
249 for (size_t i = 0; i < planes; ++i) { 308 for (size_t i = 0; i < dest_planes; ++i) {
250 int rows = VideoFrame::Rows(i, format, size.height()); 309 int rows = VideoFrame::Rows(i, output_format_, size.height());
251 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); 310 int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width());
311 // Copy a even number of lines, and at least one.
252 int rows_per_copy = 312 int rows_per_copy =
253 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); 313 std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
254 copies += rows / rows_per_copy; 314 copies += rows / rows_per_copy;
255 if (rows % rows_per_copy) 315 if (rows % rows_per_copy)
256 ++copies; 316 ++copies;
257 } 317 }
258
259 base::Closure copies_done = 318 base::Closure copies_done =
260 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, 319 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources,
261 frame_ready_cb); 320 frame_ready_cb);
262 base::Closure barrier = base::BarrierClosure(copies, copies_done); 321 base::Closure barrier = base::BarrierClosure(copies, copies_done);
322 // Post all the async tasks.
323 for (size_t i = 0; i < dest_planes; ++i) {
324 int rows = VideoFrame::Rows(i, output_format_, size.height());
325 int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width());
326 int rows_per_copy =
327 std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
263 328
264 for (size_t i = 0; i < planes; ++i) { 329 void* data = nullptr;
265 int rows = VideoFrame::Rows(i, format, size.height()); 330 CHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(
266 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); 331 GpuMemoryBufferFormat(output_format_, i)));
Avi (use Gerrit) 2015/08/21 21:32:03 DCHECK here too
Daniele Castagna 2015/08/21 21:37:08 Done.
267 int rows_per_copy = 332 bool rv = frame_resources->plane_resources[i].gpu_memory_buffer->Map(&data);
268 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); 333 DCHECK(rv);
334 uint8* mapped_buffer = static_cast<uint8*>(data);
269 335
270 PlaneResource& plane_resource = frame_resources->plane_resources[i];
271 void* data = nullptr;
272 CHECK(plane_resource.gpu_memory_buffer->Map(&data));
273 uint8* mapped_buffer = static_cast<uint8*>(data);
274 int dest_stride = 0; 336 int dest_stride = 0;
275 plane_resource.gpu_memory_buffer->GetStride(&dest_stride); 337 frame_resources->plane_resources[i].gpu_memory_buffer->GetStride(
338 &dest_stride);
276 339
277 for (int row = 0; row < rows; row += rows_per_copy) { 340 for (int row = 0; row < rows; row += rows_per_copy) {
278 worker_task_runner_->PostTask( 341 switch (output_format_) {
279 FROM_HERE, 342 case PIXEL_FORMAT_I420:
280 base::Bind(&CopyRowsToBuffer, row, 343 worker_task_runner_->PostTask(
281 std::min(rows_per_copy, rows - row), bytes_per_row, 344 FROM_HERE,
282 video_frame->data(i), video_frame->stride(i), 345 base::Bind(&CopyRowsToI420Buffer, row,
283 mapped_buffer, dest_stride, barrier)); 346 std::min(rows_per_copy, rows - row), bytes_per_row,
347 video_frame->data(i), video_frame->stride(i),
348 mapped_buffer, dest_stride, barrier));
349 break;
350 case PIXEL_FORMAT_UYVY:
351 worker_task_runner_->PostTask(
352 FROM_HERE,
353 base::Bind(&CopyRowsToUYVYBuffer, row,
354 std::min(rows_per_copy, rows - row), size.width(),
355 video_frame, mapped_buffer, dest_stride, barrier));
356 break;
357 default:
358 NOTREACHED();
359 }
284 } 360 }
285 } 361 }
286 } 362 }
287 363
288 void GpuMemoryBufferVideoFramePool::PoolImpl:: 364 void GpuMemoryBufferVideoFramePool::PoolImpl::
289 BindAndCreateMailboxesHardwareFrameResources( 365 BindAndCreateMailboxesHardwareFrameResources(
290 const scoped_refptr<VideoFrame>& video_frame, 366 const scoped_refptr<VideoFrame>& video_frame,
291 FrameResources* frame_resources, 367 FrameResources* frame_resources,
292 const FrameReadyCB& frame_ready_cb) { 368 const FrameReadyCB& frame_ready_cb) {
293 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); 369 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface();
294 if (!gles2) { 370 if (!gles2) {
295 frame_ready_cb.Run(video_frame); 371 frame_ready_cb.Run(video_frame);
296 return; 372 return;
297 } 373 }
298 374
299 const VideoPixelFormat format = video_frame->format(); 375 const size_t planes = VideoFrame::NumPlanes(output_format_);
300 const size_t planes = VideoFrame::NumPlanes(format);
301 const gfx::Size size = video_frame->visible_rect().size(); 376 const gfx::Size size = video_frame->visible_rect().size();
302 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; 377 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
303 // Set up the planes creating the mailboxes needed to refer to the textures. 378 // Set up the planes creating the mailboxes needed to refer to the textures.
304 for (size_t i = 0; i < planes; ++i) { 379 for (size_t i = 0; i < planes; ++i) {
305 PlaneResource& plane_resource = frame_resources->plane_resources[i]; 380 PlaneResource& plane_resource = frame_resources->plane_resources[i];
306 // Bind the texture and create or rebind the image. 381 // Bind the texture and create or rebind the image.
307 gles2->BindTexture(texture_target_, plane_resource.texture_id); 382 gles2->BindTexture(texture_target_, plane_resource.texture_id);
308 383
309 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { 384 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) {
310 const size_t width = VideoFrame::Columns(i, format, size.width()); 385 const size_t width = VideoFrame::Columns(i, output_format_, size.width());
311 const size_t height = VideoFrame::Rows(i, format, size.height()); 386 const size_t height = VideoFrame::Rows(i, output_format_, size.height());
312 plane_resource.image_id = gles2->CreateImageCHROMIUM( 387 plane_resource.image_id = gles2->CreateImageCHROMIUM(
313 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, 388 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height,
314 GL_R8_EXT); 389 ImageInternalFormat(output_format_, i));
315 } else { 390 } else {
316 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, 391 gles2->ReleaseTexImage2DCHROMIUM(texture_target_,
317 plane_resource.image_id); 392 plane_resource.image_id);
318 } 393 }
319 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); 394 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id);
320 mailbox_holders[i] = 395 mailbox_holders[i] =
321 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); 396 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0);
322 } 397 }
323 398
324 // Insert a sync_point, this is needed to make sure that the textures the 399 // Insert a sync_point, this is needed to make sure that the textures the
325 // mailboxes refer to will be used only after all the previous commands posted 400 // mailboxes refer to will be used only after all the previous commands posted
326 // in the command buffer have been processed. 401 // in the command buffer have been processed.
327 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); 402 unsigned sync_point = gles2->InsertSyncPointCHROMIUM();
328 for (size_t i = 0; i < planes; ++i) { 403 for (size_t i = 0; i < planes; ++i) {
329 mailbox_holders[i].sync_point = sync_point; 404 mailbox_holders[i].sync_point = sync_point;
330 } 405 }
331 406
407 scoped_refptr<VideoFrame> frame;
332 // Create the VideoFrame backed by native textures. 408 // Create the VideoFrame backed by native textures.
333 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( 409 switch (output_format_) {
334 mailbox_holders[VideoFrame::kYPlane], 410 case PIXEL_FORMAT_I420:
335 mailbox_holders[VideoFrame::kUPlane], 411 frame = VideoFrame::WrapYUV420NativeTextures(
336 mailbox_holders[VideoFrame::kVPlane], 412 mailbox_holders[VideoFrame::kYPlane],
337 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), 413 mailbox_holders[VideoFrame::kUPlane],
338 size, video_frame->visible_rect(), video_frame->natural_size(), 414 mailbox_holders[VideoFrame::kVPlane],
339 video_frame->timestamp()); 415 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
340 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) 416 size, video_frame->visible_rect(), video_frame->natural_size(),
341 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); 417 video_frame->timestamp());
418 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
419 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
420 break;
421 case PIXEL_FORMAT_UYVY:
422 frame = VideoFrame::WrapNativeTexture(
423 PIXEL_FORMAT_UYVY, mailbox_holders[VideoFrame::kYPlane],
424 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
425 size, video_frame->visible_rect(), video_frame->natural_size(),
426 video_frame->timestamp());
427 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
428 break;
429 default:
430 NOTREACHED();
431 }
342 frame_ready_cb.Run(frame); 432 frame_ready_cb.Run(frame);
343 } 433 }
344 434
345 // Destroy all the resources posting one task per FrameResources 435 // Destroy all the resources posting one task per FrameResources
346 // to the |media_task_runner_|. 436 // to the |media_task_runner_|.
347 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { 437 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() {
348 // Delete all the resources on the media thread. 438 // Delete all the resources on the media thread.
349 while (!resources_pool_.empty()) { 439 while (!resources_pool_.empty()) {
350 FrameResources* frame_resources = resources_pool_.front(); 440 FrameResources* frame_resources = resources_pool_.front();
351 resources_pool_.pop_front(); 441 resources_pool_.pop_front();
352 media_task_runner_->PostTask( 442 media_task_runner_->PostTask(
353 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, 443 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_,
354 base::Owned(frame_resources))); 444 base::Owned(frame_resources)));
355 } 445 }
356 } 446 }
357 447
358 // Tries to find the resources in the pool or create them. 448 // Tries to find the resources in the pool or create them.
359 // Incompatible resources will be dropped. 449 // Incompatible resources will be dropped.
360 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* 450 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources*
361 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( 451 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
362 const gfx::Size& size, 452 const gfx::Size& size,
363 VideoPixelFormat format) { 453 VideoPixelFormat format) {
364 auto it = resources_pool_.begin(); 454 auto it = resources_pool_.begin();
365 while (it != resources_pool_.end()) { 455 while (it != resources_pool_.end()) {
366 FrameResources* frame_resources = *it; 456 FrameResources* frame_resources = *it;
367 if (!frame_resources->in_use) { 457 if (!frame_resources->in_use) {
368 if (AreFrameResourcesCompatible(frame_resources, size, format)) { 458 if (AreFrameResourcesCompatible(frame_resources, size)) {
369 frame_resources->in_use = true; 459 frame_resources->in_use = true;
370 return frame_resources; 460 return frame_resources;
371 } else { 461 } else {
372 resources_pool_.erase(it++); 462 resources_pool_.erase(it++);
373 DeleteFrameResources(gpu_factories_, frame_resources); 463 DeleteFrameResources(gpu_factories_, frame_resources);
374 delete frame_resources; 464 delete frame_resources;
375 } 465 }
376 } else { 466 } else {
377 it++; 467 it++;
378 } 468 }
379 } 469 }
380 470
381 // Create the resources. 471 // Create the resources.
382 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); 472 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface();
383 if (!gles2) 473 if (!gles2)
384 return nullptr; 474 return nullptr;
385 gles2->ActiveTexture(GL_TEXTURE0); 475 gles2->ActiveTexture(GL_TEXTURE0);
386 size_t planes = VideoFrame::NumPlanes(format); 476 size_t planes = VideoFrame::NumPlanes(format);
387 FrameResources* frame_resources = new FrameResources(format, size); 477 FrameResources* frame_resources = new FrameResources(size);
388 resources_pool_.push_back(frame_resources); 478 resources_pool_.push_back(frame_resources);
389 for (size_t i = 0; i < planes; ++i) { 479 for (size_t i = 0; i < planes; ++i) {
390 PlaneResource& plane_resource = frame_resources->plane_resources[i]; 480 PlaneResource& plane_resource = frame_resources->plane_resources[i];
391 const size_t width = VideoFrame::Columns(i, format, size.width()); 481 const size_t width = VideoFrame::Columns(i, format, size.width());
392 const size_t height = VideoFrame::Rows(i, format, size.height()); 482 const size_t height = VideoFrame::Rows(i, format, size.height());
393 const gfx::Size plane_size(width, height); 483 const gfx::Size plane_size(width, height);
484
394 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( 485 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer(
395 plane_size, gfx::BufferFormat::R_8, gfx::BufferUsage::MAP); 486 plane_size, GpuMemoryBufferFormat(format, i), gfx::BufferUsage::MAP);
396 487
397 gles2->GenTextures(1, &plane_resource.texture_id); 488 gles2->GenTextures(1, &plane_resource.texture_id);
398 gles2->BindTexture(texture_target_, plane_resource.texture_id); 489 gles2->BindTexture(texture_target_, plane_resource.texture_id);
399 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 490 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
400 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 491 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
401 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 492 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
402 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 493 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
403 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); 494 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name);
404 gles2->ProduceTextureCHROMIUM(texture_target_, plane_resource.mailbox.name); 495 gles2->ProduceTextureCHROMIUM(texture_target_, plane_resource.mailbox.name);
405 } 496 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 } 551 }
461 552
462 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( 553 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame(
463 const scoped_refptr<VideoFrame>& video_frame, 554 const scoped_refptr<VideoFrame>& video_frame,
464 const FrameReadyCB& frame_ready_cb) { 555 const FrameReadyCB& frame_ready_cb) {
465 DCHECK(video_frame); 556 DCHECK(video_frame);
466 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); 557 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb);
467 } 558 }
468 559
469 } // namespace media 560 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/mock_gpu_video_accelerator_factories.cc ('k') | media/video/gpu_memory_buffer_video_frame_pool_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698