OLD | NEW |
| (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 | |
OLD | NEW |