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

Side by Side Diff: content/common/gpu/media/gpu_video_encode_accelerator.cc

Issue 1882373004: Migrate content/common/gpu/media code to media/gpu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Squash and rebase Created 4 years, 7 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 2013 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 "content/common/gpu/media/gpu_video_encode_accelerator.h"
6
7 #include <memory>
8
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/shared_memory.h"
14 #include "base/numerics/safe_math.h"
15 #include "base/sys_info.h"
16 #include "build/build_config.h"
17 #include "gpu/ipc/client/gpu_memory_buffer_impl.h"
18 #include "gpu/ipc/service/gpu_channel.h"
19 #include "gpu/ipc/service/gpu_channel_manager.h"
20 #include "ipc/ipc_message_macros.h"
21 #include "media/base/bind_to_current_loop.h"
22 #include "media/base/limits.h"
23 #include "media/base/video_frame.h"
24 #include "media/gpu/ipc/common/gpu_video_accelerator_util.h"
25 #include "media/gpu/ipc/common/media_messages.h"
26
27 #if defined(OS_CHROMEOS)
28 #if defined(USE_V4L2_CODEC)
29 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
30 #endif
31 #if defined(ARCH_CPU_X86_FAMILY)
32 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
33 #endif
34 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
35 #include "content/common/gpu/media/android_video_encode_accelerator.h"
36 #elif defined(OS_MACOSX)
37 #include "content/common/gpu/media/vt_video_encode_accelerator_mac.h"
38 #endif
39
40 namespace content {
41
42 static bool MakeDecoderContextCurrent(
43 const base::WeakPtr<gpu::GpuCommandBufferStub> stub) {
44 if (!stub) {
45 DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
46 return false;
47 }
48
49 if (!stub->decoder()->MakeCurrent()) {
50 DLOG(ERROR) << "Failed to MakeCurrent()";
51 return false;
52 }
53
54 return true;
55 }
56
57 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(
58 int32_t host_route_id,
59 gpu::GpuCommandBufferStub* stub)
60 : host_route_id_(host_route_id),
61 stub_(stub),
62 input_format_(media::PIXEL_FORMAT_UNKNOWN),
63 output_buffer_size_(0),
64 weak_this_factory_(this) {
65 stub_->AddDestructionObserver(this);
66 make_context_current_ =
67 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
68 }
69
70 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
71 // This class can only be self-deleted from OnWillDestroyStub(), which means
72 // the VEA has already been destroyed in there.
73 DCHECK(!encoder_);
74 }
75
76 bool GpuVideoEncodeAccelerator::Initialize(
77 media::VideoPixelFormat input_format,
78 const gfx::Size& input_visible_size,
79 media::VideoCodecProfile output_profile,
80 uint32_t initial_bitrate) {
81 DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): "
82 "input_format=" << input_format
83 << ", input_visible_size=" << input_visible_size.ToString()
84 << ", output_profile=" << output_profile
85 << ", initial_bitrate=" << initial_bitrate;
86 DCHECK(!encoder_);
87
88 if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) {
89 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
90 "failed to add route";
91 return false;
92 }
93
94 if (input_visible_size.width() > media::limits::kMaxDimension ||
95 input_visible_size.height() > media::limits::kMaxDimension ||
96 input_visible_size.GetArea() > media::limits::kMaxCanvas) {
97 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
98 "input_visible_size " << input_visible_size.ToString()
99 << " too large";
100 return false;
101 }
102
103 const gpu::GpuPreferences& gpu_preferences =
104 stub_->channel()->gpu_channel_manager()->gpu_preferences();
105
106 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps =
107 CreateVEAFps(gpu_preferences);
108 // Try all possible encoders and use the first successful encoder.
109 for (size_t i = 0; i < create_vea_fps.size(); ++i) {
110 encoder_ = (*create_vea_fps[i])();
111 if (encoder_ && encoder_->Initialize(input_format,
112 input_visible_size,
113 output_profile,
114 initial_bitrate,
115 this)) {
116 input_format_ = input_format;
117 input_visible_size_ = input_visible_size;
118 return true;
119 }
120 }
121 encoder_.reset();
122 DLOG(ERROR)
123 << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
124 return false;
125 }
126
127 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
128 bool handled = true;
129 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
130 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
131 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode2, OnEncode2)
132 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
133 OnUseOutputBitstreamBuffer)
134 IPC_MESSAGE_HANDLER(
135 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
136 OnRequestEncodingParametersChange)
137 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
138 IPC_MESSAGE_UNHANDLED(handled = false)
139 IPC_END_MESSAGE_MAP()
140 return handled;
141 }
142
143 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
144 unsigned int input_count,
145 const gfx::Size& input_coded_size,
146 size_t output_buffer_size) {
147 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
148 host_route_id_, input_count, input_coded_size, output_buffer_size));
149 input_coded_size_ = input_coded_size;
150 output_buffer_size_ = output_buffer_size;
151 }
152
153 void GpuVideoEncodeAccelerator::BitstreamBufferReady(
154 int32_t bitstream_buffer_id,
155 size_t payload_size,
156 bool key_frame) {
157 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
158 host_route_id_, bitstream_buffer_id, payload_size, key_frame));
159 }
160
161 void GpuVideoEncodeAccelerator::NotifyError(
162 media::VideoEncodeAccelerator::Error error) {
163 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
164 }
165
166 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
167 DCHECK(stub_);
168 stub_->channel()->RemoveRoute(host_route_id_);
169 stub_->RemoveDestructionObserver(this);
170 encoder_.reset();
171 delete this;
172 }
173
174 // static
175 gpu::VideoEncodeAcceleratorSupportedProfiles
176 GpuVideoEncodeAccelerator::GetSupportedProfiles(
177 const gpu::GpuPreferences& gpu_preferences) {
178 media::VideoEncodeAccelerator::SupportedProfiles profiles;
179 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps =
180 CreateVEAFps(gpu_preferences);
181
182 for (size_t i = 0; i < create_vea_fps.size(); ++i) {
183 std::unique_ptr<media::VideoEncodeAccelerator> encoder =
184 (*create_vea_fps[i])();
185 if (!encoder)
186 continue;
187 media::VideoEncodeAccelerator::SupportedProfiles vea_profiles =
188 encoder->GetSupportedProfiles();
189 media::GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles(vea_profiles,
190 &profiles);
191 }
192 return media::GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(
193 profiles);
194 }
195
196 // static
197 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
198 GpuVideoEncodeAccelerator::CreateVEAFps(
199 const gpu::GpuPreferences& gpu_preferences) {
200 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps;
201 #if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
202 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateV4L2VEA);
203 #endif
204 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
205 if (!gpu_preferences.disable_vaapi_accelerated_video_encode)
206 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVaapiVEA);
207 #endif
208 #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
209 if (!gpu_preferences.disable_web_rtc_hw_encoding)
210 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateAndroidVEA);
211 #endif
212 #if defined(OS_MACOSX)
213 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVTVEA);
214 #endif
215 return create_vea_fps;
216 }
217
218 #if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
219 // static
220 std::unique_ptr<media::VideoEncodeAccelerator>
221 GpuVideoEncodeAccelerator::CreateV4L2VEA() {
222 std::unique_ptr<media::VideoEncodeAccelerator> encoder;
223 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
224 if (device)
225 encoder.reset(new V4L2VideoEncodeAccelerator(device));
226 return encoder;
227 }
228 #endif
229
230 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
231 // static
232 std::unique_ptr<media::VideoEncodeAccelerator>
233 GpuVideoEncodeAccelerator::CreateVaapiVEA() {
234 return base::WrapUnique<media::VideoEncodeAccelerator>(
235 new VaapiVideoEncodeAccelerator());
236 }
237 #endif
238
239 #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
240 // static
241 std::unique_ptr<media::VideoEncodeAccelerator>
242 GpuVideoEncodeAccelerator::CreateAndroidVEA() {
243 return base::WrapUnique<media::VideoEncodeAccelerator>(
244 new AndroidVideoEncodeAccelerator());
245 }
246 #endif
247
248 #if defined(OS_MACOSX)
249 // static
250 std::unique_ptr<media::VideoEncodeAccelerator>
251 GpuVideoEncodeAccelerator::CreateVTVEA() {
252 return base::WrapUnique<media::VideoEncodeAccelerator>(
253 new VTVideoEncodeAccelerator());
254 }
255 #endif
256
257 void GpuVideoEncodeAccelerator::OnEncode(
258 const AcceleratedVideoEncoderMsg_Encode_Params& params) {
259 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode: frame_id = "
260 << params.frame_id << ", buffer_size=" << params.buffer_size
261 << ", force_keyframe=" << params.force_keyframe;
262 DCHECK_EQ(media::PIXEL_FORMAT_I420, input_format_);
263
264 // Wrap into a SharedMemory in the beginning, so that |params.buffer_handle|
265 // is cleaned properly in case of an early return.
266 std::unique_ptr<base::SharedMemory> shm(
267 new base::SharedMemory(params.buffer_handle, true));
268
269 if (!encoder_)
270 return;
271
272 if (params.frame_id < 0) {
273 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid "
274 "frame_id=" << params.frame_id;
275 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
276 return;
277 }
278
279 const uint32_t aligned_offset =
280 params.buffer_offset % base::SysInfo::VMAllocationGranularity();
281 base::CheckedNumeric<off_t> map_offset = params.buffer_offset;
282 map_offset -= aligned_offset;
283 base::CheckedNumeric<size_t> map_size = params.buffer_size;
284 map_size += aligned_offset;
285
286 if (!map_offset.IsValid() || !map_size.IsValid()) {
287 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode():"
288 << " invalid (buffer_offset,buffer_size)";
289 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
290 return;
291 }
292
293 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
294 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
295 << "could not map frame_id=" << params.frame_id;
296 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
297 return;
298 }
299
300 uint8_t* shm_memory =
301 reinterpret_cast<uint8_t*>(shm->memory()) + aligned_offset;
302 scoped_refptr<media::VideoFrame> frame =
303 media::VideoFrame::WrapExternalSharedMemory(
304 input_format_,
305 input_coded_size_,
306 gfx::Rect(input_visible_size_),
307 input_visible_size_,
308 shm_memory,
309 params.buffer_size,
310 params.buffer_handle,
311 params.buffer_offset,
312 params.timestamp);
313 if (!frame) {
314 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
315 << "could not create a frame";
316 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
317 return;
318 }
319 frame->AddDestructionObserver(
320 media::BindToCurrentLoop(
321 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
322 weak_this_factory_.GetWeakPtr(),
323 params.frame_id,
324 base::Passed(&shm))));
325 encoder_->Encode(frame, params.force_keyframe);
326 }
327
328 void GpuVideoEncodeAccelerator::OnEncode2(
329 const AcceleratedVideoEncoderMsg_Encode_Params2& params) {
330 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode2: frame_id = "
331 << params.frame_id << ", size=" << params.size.ToString()
332 << ", force_keyframe=" << params.force_keyframe << ", handle type="
333 << params.gpu_memory_buffer_handles[0].type;
334 // Encoding GpuMemoryBuffer backed frames is not supported.
335 NOTREACHED();
336 }
337
338 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
339 int32_t buffer_id,
340 base::SharedMemoryHandle buffer_handle,
341 uint32_t buffer_size) {
342 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
343 "buffer_id=" << buffer_id
344 << ", buffer_size=" << buffer_size;
345 if (!encoder_)
346 return;
347 if (buffer_id < 0) {
348 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
349 "invalid buffer_id=" << buffer_id;
350 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
351 return;
352 }
353 if (buffer_size < output_buffer_size_) {
354 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
355 "buffer too small for buffer_id=" << buffer_id;
356 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
357 return;
358 }
359 encoder_->UseOutputBitstreamBuffer(
360 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
361 }
362
363 void GpuVideoEncodeAccelerator::OnDestroy() {
364 DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
365 OnWillDestroyStub();
366 }
367
368 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
369 uint32_t bitrate,
370 uint32_t framerate) {
371 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
372 "bitrate=" << bitrate
373 << ", framerate=" << framerate;
374 if (!encoder_)
375 return;
376 encoder_->RequestEncodingParametersChange(bitrate, framerate);
377 }
378
379 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
380 int32_t frame_id,
381 std::unique_ptr<base::SharedMemory> shm) {
382 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
383 frame_id));
384 // Just let |shm| fall out of scope.
385 }
386
387 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
388 stub_->channel()->Send(message);
389 }
390
391 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698