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

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

Issue 1874733002: media: split GpuMemoryBufferVideoFramePool into GpuMemoryBufferVideoFrameCopier/Pool Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add GpuMemoryBufferVideoFramePoolTest Created 4 years, 8 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/video/gpu_memory_buffer_video_frame_copier.h"
6
7 #include "base/barrier_closure.h"
8 #include "base/bind.h"
9 #include "media/renderers/gpu_video_accelerator_factories.h"
10 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
11 #include "third_party/libyuv/include/libyuv.h"
12
13 namespace media {
14
15 class GpuMemoryBufferVideoFrameCopier::CopierImpl
16 : public base::RefCountedThreadSafe<
17 GpuMemoryBufferVideoFrameCopier::CopierImpl> {
18 public:
19 // |media_task_runner| is the media task runner associated with the
20 // GL context provided by |gpu_factories|
21 // |worker_task_runner| is a task runner used to asynchronously copy
22 // video frame's planes.
23 // |gpu_factories| is an interface to GPU related operation and can be
24 // null if a GL context is not available.
25 CopierImpl(
26 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
27 const scoped_refptr<base::TaskRunner>& worker_task_runner,
28 GpuVideoAcceleratorFactories* gpu_factories)
29 : media_task_runner_(media_task_runner),
30 worker_task_runner_(worker_task_runner),
31 gpu_factories_(gpu_factories),
32 video_frame_pool_(new GpuMemoryBufferVideoFramePool(media_task_runner_,
33 gpu_factories)),
34 output_format_(PIXEL_FORMAT_UNKNOWN) {
35 DCHECK(media_task_runner_);
36 DCHECK(worker_task_runner_);
37 }
38
39 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame
40 // backed by native textures if possible.
41 // The data contained in video_frame is copied into the returned frame
42 // asynchronously posting tasks to |worker_task_runner_|, while
43 // |frame_ready_cb| will be called on |media_task_runner_| once all the data
44 // has been copied.
45 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame,
46 const FrameReadyCB& cb);
47
48 private:
49 friend class base::RefCountedThreadSafe<
50 GpuMemoryBufferVideoFrameCopier::CopierImpl>;
51 ~CopierImpl();
52
53 // Copy |video_frame| data into |video_frame_future|
54 // and calls |frame_ready_cb| when done.
55 void CopyVideoFrameToGpuMemoryBuffers(
56 const scoped_refptr<VideoFrame>& video_frame,
57 std::unique_ptr<VideoFrameFuture> video_frame_future,
58 const FrameReadyCB& frame_ready_cb);
59
60 // Called when all the data has been copied.
61 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame,
62 std::unique_ptr<VideoFrameFuture> video_frame_future,
63 const FrameReadyCB& frame_ready_cb);
64
65 // Create new VideoFrame by |video_frame_future| and calls |frame_ready_cb|.
66 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also
67 // be run.
68 void CreateGpuMemoryBufferVideoFrame(
69 const scoped_refptr<VideoFrame>& video_frame,
70 std::unique_ptr<VideoFrameFuture> video_frame_future,
71 const FrameReadyCB& frame_ready_cb);
72
73 // Task runner associated to the GL context provided by |gpu_factories_|.
74 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
75 // Task runner used to asynchronously copy planes.
76 scoped_refptr<base::TaskRunner> worker_task_runner_;
77
78 // Interface to GPU related operations.
79 GpuVideoAcceleratorFactories* gpu_factories_;
80
81 std::unique_ptr<GpuMemoryBufferVideoFramePool> video_frame_pool_;
82
83 // TODO(dcastagna): change the following type from VideoPixelFormat to
84 // BufferFormat.
85 VideoPixelFormat output_format_;
86
87 DISALLOW_COPY_AND_ASSIGN(CopierImpl);
88 };
89
90 namespace {
91
92 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the
93 // output size is |kBytesPerCopyTarget| bytes and run in parallel.
94 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB
95
96 // The number of output rows to be copied in each iteration.
97 int RowsPerCopy(size_t plane, VideoPixelFormat format, int width) {
98 int bytes_per_row = VideoFrame::RowBytes(plane, format, width);
99 if (format == PIXEL_FORMAT_NV12) {
100 DCHECK_EQ(0u, plane);
101 bytes_per_row += VideoFrame::RowBytes(1, format, width);
102 }
103 // Copy an even number of lines, and at least one.
104 return std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
105 }
106
107 void CopyRowsToI420Buffer(int first_row,
108 int rows,
109 int bytes_per_row,
110 const uint8_t* source,
111 int source_stride,
112 uint8_t* output,
113 int dest_stride,
114 const base::Closure& done) {
115 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row,
116 "rows", rows);
117 if (output) {
118 DCHECK_NE(dest_stride, 0);
119 DCHECK_LE(bytes_per_row, std::abs(dest_stride));
120 DCHECK_LE(bytes_per_row, source_stride);
121
122 libyuv::CopyPlane(source + source_stride * first_row, source_stride,
123 output + dest_stride * first_row, dest_stride,
124 bytes_per_row, rows);
125 }
126 done.Run();
127 }
128
129 void CopyRowsToNV12Buffer(int first_row,
130 int rows,
131 int bytes_per_row,
132 const scoped_refptr<VideoFrame>& source_frame,
133 uint8_t* dest_y,
134 int dest_stride_y,
135 uint8_t* dest_uv,
136 int dest_stride_uv,
137 const base::Closure& done) {
138 TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row,
139 "rows", rows);
140 if (dest_y && dest_uv) {
141 DCHECK_NE(dest_stride_y, 0);
142 DCHECK_NE(dest_stride_uv, 0);
143 DCHECK_LE(bytes_per_row, std::abs(dest_stride_y));
144 DCHECK_LE(bytes_per_row, std::abs(dest_stride_uv));
145 DCHECK_EQ(0, first_row % 2);
146
147 libyuv::I420ToNV12(
148 source_frame->visible_data(VideoFrame::kYPlane) +
149 first_row * source_frame->stride(VideoFrame::kYPlane),
150 source_frame->stride(VideoFrame::kYPlane),
151 source_frame->visible_data(VideoFrame::kUPlane) +
152 first_row / 2 * source_frame->stride(VideoFrame::kUPlane),
153 source_frame->stride(VideoFrame::kUPlane),
154 source_frame->visible_data(VideoFrame::kVPlane) +
155 first_row / 2 * source_frame->stride(VideoFrame::kVPlane),
156 source_frame->stride(VideoFrame::kVPlane),
157 dest_y + first_row * dest_stride_y, dest_stride_y,
158 dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv, bytes_per_row,
159 rows);
160 }
161 done.Run();
162 }
163
164 void CopyRowsToUYVYBuffer(int first_row,
165 int rows,
166 int width,
167 const scoped_refptr<VideoFrame>& source_frame,
168 uint8_t* output,
169 int dest_stride,
170 const base::Closure& done) {
171 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2,
172 "rows", rows);
173 if (output) {
174 DCHECK_NE(dest_stride, 0);
175 DCHECK_LE(width, std::abs(dest_stride / 2));
176 DCHECK_EQ(0, first_row % 2);
177 libyuv::I420ToUYVY(
178 source_frame->visible_data(VideoFrame::kYPlane) +
179 first_row * source_frame->stride(VideoFrame::kYPlane),
180 source_frame->stride(VideoFrame::kYPlane),
181 source_frame->visible_data(VideoFrame::kUPlane) +
182 first_row / 2 * source_frame->stride(VideoFrame::kUPlane),
183 source_frame->stride(VideoFrame::kUPlane),
184 source_frame->visible_data(VideoFrame::kVPlane) +
185 first_row / 2 * source_frame->stride(VideoFrame::kVPlane),
186 source_frame->stride(VideoFrame::kVPlane),
187 output + first_row * dest_stride, dest_stride, width, rows);
188 }
189 done.Run();
190 }
191
192 } // unnamed namespace
193
194 // Creates a VideoFrame backed by native textures starting from a software
195 // VideoFrame.
196 // The data contained in |video_frame| is copied into the VideoFrame passed to
197 // |frame_ready_cb|.
198 // This has to be called on the thread where |media_task_runner_| is current.
199 void GpuMemoryBufferVideoFrameCopier::CopierImpl::CreateHardwareFrame(
200 const scoped_refptr<VideoFrame>& video_frame,
201 const FrameReadyCB& frame_ready_cb) {
202 DCHECK(media_task_runner_->BelongsToCurrentThread());
203 // Lazily initialize output_format_ since VideoFrameOutputFormat() has to be
204 // called on the media_thread while this object might be instantiated on any.
205 if (output_format_ == PIXEL_FORMAT_UNKNOWN)
206 output_format_ = gpu_factories_->VideoFrameOutputFormat();
207
208 if (output_format_ == PIXEL_FORMAT_UNKNOWN) {
209 frame_ready_cb.Run(video_frame);
210 return;
211 }
212
213 if (video_frame->HasTextures()) {
214 frame_ready_cb.Run(video_frame);
215 return;
216 }
217
218 switch (video_frame->format()) {
219 // Supported cases.
220 case PIXEL_FORMAT_YV12:
221 case PIXEL_FORMAT_I420:
222 break;
223 // Unsupported cases.
224 case PIXEL_FORMAT_YV12A:
225 case PIXEL_FORMAT_YV16:
226 case PIXEL_FORMAT_YV24:
227 case PIXEL_FORMAT_NV12:
228 case PIXEL_FORMAT_NV21:
229 case PIXEL_FORMAT_UYVY:
230 case PIXEL_FORMAT_YUY2:
231 case PIXEL_FORMAT_ARGB:
232 case PIXEL_FORMAT_XRGB:
233 case PIXEL_FORMAT_RGB24:
234 case PIXEL_FORMAT_RGB32:
235 case PIXEL_FORMAT_MJPEG:
236 case PIXEL_FORMAT_MT21:
237 case PIXEL_FORMAT_YUV420P9:
238 case PIXEL_FORMAT_YUV422P9:
239 case PIXEL_FORMAT_YUV444P9:
240 case PIXEL_FORMAT_YUV420P10:
241 case PIXEL_FORMAT_YUV422P10:
242 case PIXEL_FORMAT_YUV444P10:
243 case PIXEL_FORMAT_UNKNOWN:
244 frame_ready_cb.Run(video_frame);
245 return;
246 }
247
248 std::unique_ptr<VideoFrameFuture> video_frame_future =
249 video_frame_pool_->CreateFrame(
250 output_format_, video_frame->visible_rect().size(),
251 video_frame->visible_rect(), video_frame->natural_size(),
252 video_frame->timestamp());
253 if (!video_frame_future) {
254 frame_ready_cb.Run(video_frame);
255 return;
256 }
257
258 worker_task_runner_->PostTask(
259 FROM_HERE,
260 base::Bind(&CopierImpl::CopyVideoFrameToGpuMemoryBuffers, this,
261 video_frame, base::Passed(std::move(video_frame_future)),
262 frame_ready_cb));
263 }
264
265 void GpuMemoryBufferVideoFrameCopier::CopierImpl::OnCopiesDone(
266 const scoped_refptr<VideoFrame>& video_frame,
267 std::unique_ptr<VideoFrameFuture> video_frame_future,
268 const FrameReadyCB& frame_ready_cb) {
269 media_task_runner_->PostTask(
270 FROM_HERE,
271 base::Bind(&CopierImpl::CreateGpuMemoryBufferVideoFrame, this,
272 video_frame, base::Passed(std::move(video_frame_future)),
273 frame_ready_cb));
274 }
275
276 // Copies |video_frame| into |video_frame_future| asynchronously, posting n
277 // tasks that will be synchronized by a barrier.
278 // After the barrier is passed OnCopiesDone will be called.
279 void GpuMemoryBufferVideoFrameCopier::CopierImpl::
280 CopyVideoFrameToGpuMemoryBuffers(
281 const scoped_refptr<VideoFrame>& video_frame,
282 std::unique_ptr<VideoFrameFuture> video_frame_future,
283 const FrameReadyCB& frame_ready_cb) {
284 // Compute the number of tasks to post and create the barrier.
285 const size_t num_planes = VideoFrame::NumPlanes(output_format_);
286 const gfx::Size coded_size = video_frame_future->coded_size();
287 size_t copies = 0;
288 for (size_t i = 0; i < num_planes;
289 i += GpuMemoryBufferVideoFramePool::PlanesPerCopy(output_format_, i)) {
290 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height());
291 const int rows_per_copy =
292 RowsPerCopy(i, output_format_, coded_size.width());
293 copies += rows / rows_per_copy;
294 if (rows % rows_per_copy)
295 ++copies;
296 }
297
298 VideoFrameFuture* future_ptr = video_frame_future.get();
299 const base::Closure copies_done =
300 base::Bind(&CopierImpl::OnCopiesDone, this, video_frame,
301 base::Passed(std::move(video_frame_future)), frame_ready_cb);
302 const base::Closure barrier = base::BarrierClosure(copies, copies_done);
303
304 // Post all the async tasks.
305 for (size_t i = 0; i < num_planes;
306 i += GpuMemoryBufferVideoFramePool::PlanesPerCopy(output_format_, i)) {
307 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height());
308 const int rows_per_copy =
309 RowsPerCopy(i, output_format_, coded_size.width());
310
311 for (int row = 0; row < rows; row += rows_per_copy) {
312 const int rows_to_copy = std::min(rows_per_copy, rows - row);
313 switch (output_format_) {
314 case PIXEL_FORMAT_I420: {
315 const int bytes_per_row =
316 VideoFrame::RowBytes(i, output_format_, coded_size.width());
317 worker_task_runner_->PostTask(
318 FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy,
319 bytes_per_row, video_frame->visible_data(i),
320 video_frame->stride(i), future_ptr->data(i),
321 future_ptr->stride(i), barrier));
322 break;
323 }
324 case PIXEL_FORMAT_NV12:
325 DCHECK(i == 0);
326 worker_task_runner_->PostTask(
327 FROM_HERE,
328 base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy,
329 coded_size.width(), video_frame, future_ptr->data(0),
330 future_ptr->stride(0), future_ptr->data(1),
331 future_ptr->stride(1), barrier));
332 break;
333 case PIXEL_FORMAT_UYVY:
334 worker_task_runner_->PostTask(
335 FROM_HERE,
336 base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy,
337 coded_size.width(), video_frame, future_ptr->data(i),
338 future_ptr->stride(i), barrier));
339 break;
340 default:
341 NOTREACHED();
342 }
343 }
344 }
345 }
346
347 void GpuMemoryBufferVideoFrameCopier::CopierImpl::
348 CreateGpuMemoryBufferVideoFrame(
349 const scoped_refptr<VideoFrame>& video_frame,
350 std::unique_ptr<VideoFrameFuture> video_frame_future,
351 const FrameReadyCB& frame_ready_cb) {
352 scoped_refptr<VideoFrame> new_frame = video_frame_future->Release();
353 if (!new_frame) {
354 frame_ready_cb.Run(video_frame);
355 return;
356 }
357
358 if (new_frame && new_frame->format() == PIXEL_FORMAT_I420 &&
359 video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
360 new_frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
361
362 base::TimeTicks render_time;
363 if (video_frame->metadata()->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME,
364 &render_time)) {
365 new_frame->metadata()->SetTimeTicks(VideoFrameMetadata::REFERENCE_TIME,
366 render_time);
367 }
368
369 frame_ready_cb.Run(new_frame);
370 }
371
372 GpuMemoryBufferVideoFrameCopier::CopierImpl::~CopierImpl() {}
373
374 GpuMemoryBufferVideoFrameCopier::GpuMemoryBufferVideoFrameCopier() {}
375
376 GpuMemoryBufferVideoFrameCopier::GpuMemoryBufferVideoFrameCopier(
377 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
378 const scoped_refptr<base::TaskRunner>& worker_task_runner,
379 GpuVideoAcceleratorFactories* gpu_factories)
380 : copier_impl_(new CopierImpl(media_task_runner,
381 worker_task_runner,
382 gpu_factories)) {}
383
384 GpuMemoryBufferVideoFrameCopier::~GpuMemoryBufferVideoFrameCopier() {}
385
386 void GpuMemoryBufferVideoFrameCopier::MaybeCreateHardwareFrame(
387 const scoped_refptr<VideoFrame>& video_frame,
388 const FrameReadyCB& frame_ready_cb) {
389 DCHECK(video_frame);
390 copier_impl_->CreateHardwareFrame(video_frame, frame_ready_cb);
391 }
392
393 } // namespace media
OLDNEW
« no previous file with comments | « media/video/gpu_memory_buffer_video_frame_copier.h ('k') | media/video/gpu_memory_buffer_video_frame_copier_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698