[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / content / common / gpu / media / gpu_video_encode_accelerator.cc
blob0c3e887b5bbccb8b7a5b66cfdeb2e080bb9e11d3
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.
5 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/sys_info.h"
13 #include "build/build_config.h"
14 #include "content/common/gpu/gpu_channel.h"
15 #include "content/common/gpu/gpu_messages.h"
16 #include "content/common/gpu/media/gpu_video_accelerator_util.h"
17 #include "content/public/common/content_switches.h"
18 #include "ipc/ipc_message_macros.h"
19 #include "media/base/bind_to_current_loop.h"
20 #include "media/base/limits.h"
21 #include "media/base/video_frame.h"
23 #if defined(OS_CHROMEOS)
24 #if defined(USE_V4L2_CODEC)
25 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
26 #endif
27 #if defined(ARCH_CPU_X86_FAMILY)
28 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
29 #endif
30 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
31 #include "content/common/gpu/media/android_video_encode_accelerator.h"
32 #endif
34 namespace content {
36 static bool MakeDecoderContextCurrent(
37 const base::WeakPtr<GpuCommandBufferStub> stub) {
38 if (!stub) {
39 DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
40 return false;
43 if (!stub->decoder()->MakeCurrent()) {
44 DLOG(ERROR) << "Failed to MakeCurrent()";
45 return false;
48 return true;
51 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id,
52 GpuCommandBufferStub* stub)
53 : host_route_id_(host_route_id),
54 stub_(stub),
55 input_format_(media::VideoFrame::UNKNOWN),
56 output_buffer_size_(0),
57 weak_this_factory_(this) {
58 stub_->AddDestructionObserver(this);
59 make_context_current_ =
60 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
63 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
64 // This class can only be self-deleted from OnWillDestroyStub(), which means
65 // the VEA has already been destroyed in there.
66 DCHECK(!encoder_);
69 void GpuVideoEncodeAccelerator::Initialize(
70 media::VideoFrame::Format input_format,
71 const gfx::Size& input_visible_size,
72 media::VideoCodecProfile output_profile,
73 uint32 initial_bitrate,
74 IPC::Message* init_done_msg) {
75 DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): "
76 "input_format=" << input_format
77 << ", input_visible_size=" << input_visible_size.ToString()
78 << ", output_profile=" << output_profile
79 << ", initial_bitrate=" << initial_bitrate;
80 DCHECK(!encoder_);
82 if (!stub_->channel()->AddRoute(host_route_id_, this)) {
83 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
84 "failed to add route";
85 SendCreateEncoderReply(init_done_msg, false);
86 return;
89 if (input_visible_size.width() > media::limits::kMaxDimension ||
90 input_visible_size.height() > media::limits::kMaxDimension ||
91 input_visible_size.GetArea() > media::limits::kMaxCanvas) {
92 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
93 "input_visible_size " << input_visible_size.ToString()
94 << " too large";
95 SendCreateEncoderReply(init_done_msg, false);
96 return;
99 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
100 create_vea_fps = CreateVEAFps();
101 // Try all possible encoders and use the first successful encoder.
102 for (size_t i = 0; i < create_vea_fps.size(); ++i) {
103 encoder_ = (*create_vea_fps[i])();
104 if (encoder_ && encoder_->Initialize(input_format,
105 input_visible_size,
106 output_profile,
107 initial_bitrate,
108 this)) {
109 input_format_ = input_format;
110 input_visible_size_ = input_visible_size;
111 SendCreateEncoderReply(init_done_msg, true);
112 return;
115 encoder_.reset();
116 DLOG(ERROR)
117 << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
118 SendCreateEncoderReply(init_done_msg, false);
121 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
122 bool handled = true;
123 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
124 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
125 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
126 OnUseOutputBitstreamBuffer)
127 IPC_MESSAGE_HANDLER(
128 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
129 OnRequestEncodingParametersChange)
130 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
131 IPC_MESSAGE_UNHANDLED(handled = false)
132 IPC_END_MESSAGE_MAP()
133 return handled;
136 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
137 unsigned int input_count,
138 const gfx::Size& input_coded_size,
139 size_t output_buffer_size) {
140 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
141 host_route_id_, input_count, input_coded_size, output_buffer_size));
142 input_coded_size_ = input_coded_size;
143 output_buffer_size_ = output_buffer_size;
146 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
147 size_t payload_size,
148 bool key_frame) {
149 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
150 host_route_id_, bitstream_buffer_id, payload_size, key_frame));
153 void GpuVideoEncodeAccelerator::NotifyError(
154 media::VideoEncodeAccelerator::Error error) {
155 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
158 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
159 DCHECK(stub_);
160 stub_->channel()->RemoveRoute(host_route_id_);
161 stub_->RemoveDestructionObserver(this);
162 encoder_.reset();
163 delete this;
166 // static
167 gpu::VideoEncodeAcceleratorSupportedProfiles
168 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
169 media::VideoEncodeAccelerator::SupportedProfiles profiles;
170 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
171 create_vea_fps = CreateVEAFps();
173 for (size_t i = 0; i < create_vea_fps.size(); ++i) {
174 scoped_ptr<media::VideoEncodeAccelerator>
175 encoder = (*create_vea_fps[i])();
176 if (!encoder)
177 continue;
178 media::VideoEncodeAccelerator::SupportedProfiles vea_profiles =
179 encoder->GetSupportedProfiles();
180 GpuVideoAcceleratorUtil::InsertUniqueEncodeProfiles(
181 vea_profiles, &profiles);
183 return GpuVideoAcceleratorUtil::ConvertMediaToGpuEncodeProfiles(profiles);
186 // static
187 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp>
188 GpuVideoEncodeAccelerator::CreateVEAFps() {
189 std::vector<GpuVideoEncodeAccelerator::CreateVEAFp> create_vea_fps;
190 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateV4L2VEA);
191 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVaapiVEA);
192 create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateAndroidVEA);
193 return create_vea_fps;
196 // static
197 scoped_ptr<media::VideoEncodeAccelerator>
198 GpuVideoEncodeAccelerator::CreateV4L2VEA() {
199 scoped_ptr<media::VideoEncodeAccelerator> encoder;
200 #if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
201 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
202 if (device)
203 encoder.reset(new V4L2VideoEncodeAccelerator(device));
204 #endif
205 return encoder.Pass();
208 // static
209 scoped_ptr<media::VideoEncodeAccelerator>
210 GpuVideoEncodeAccelerator::CreateVaapiVEA() {
211 scoped_ptr<media::VideoEncodeAccelerator> encoder;
212 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
213 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
214 if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
215 encoder.reset(new VaapiVideoEncodeAccelerator());
216 #endif
217 return encoder.Pass();
220 // static
221 scoped_ptr<media::VideoEncodeAccelerator>
222 GpuVideoEncodeAccelerator::CreateAndroidVEA() {
223 scoped_ptr<media::VideoEncodeAccelerator> encoder;
224 #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
225 encoder.reset(new AndroidVideoEncodeAccelerator());
226 #endif
227 return encoder.Pass();
230 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
231 base::SharedMemoryHandle buffer_handle,
232 uint32 buffer_offset,
233 uint32 buffer_size,
234 bool force_keyframe) {
235 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
236 << ", buffer_size=" << buffer_size
237 << ", force_keyframe=" << force_keyframe;
238 if (!encoder_)
239 return;
240 if (frame_id < 0) {
241 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
242 << frame_id;
243 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
244 return;
247 uint32 aligned_offset =
248 buffer_offset % base::SysInfo::VMAllocationGranularity();
249 base::CheckedNumeric<off_t> map_offset = buffer_offset;
250 map_offset -= aligned_offset;
251 base::CheckedNumeric<size_t> map_size = buffer_size;
252 map_size += aligned_offset;
254 if (!map_offset.IsValid() || !map_size.IsValid()) {
255 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode():"
256 << " invalid (buffer_offset,buffer_size)";
257 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
258 return;
261 scoped_ptr<base::SharedMemory> shm(
262 new base::SharedMemory(buffer_handle, true));
263 if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
264 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
265 "could not map frame_id=" << frame_id;
266 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
267 return;
270 uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory()) + aligned_offset;
271 scoped_refptr<media::VideoFrame> frame =
272 media::VideoFrame::WrapExternalSharedMemory(
273 input_format_,
274 input_coded_size_,
275 gfx::Rect(input_visible_size_),
276 input_visible_size_,
277 shm_memory,
278 buffer_size,
279 buffer_handle,
280 buffer_offset,
281 base::TimeDelta());
282 frame->AddDestructionObserver(
283 media::BindToCurrentLoop(
284 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
285 weak_this_factory_.GetWeakPtr(),
286 frame_id,
287 base::Passed(&shm))));
289 if (!frame.get()) {
290 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
291 "could not create VideoFrame for frame_id=" << frame_id;
292 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
293 return;
296 encoder_->Encode(frame, force_keyframe);
299 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
300 int32 buffer_id,
301 base::SharedMemoryHandle buffer_handle,
302 uint32 buffer_size) {
303 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
304 "buffer_id=" << buffer_id
305 << ", buffer_size=" << buffer_size;
306 if (!encoder_)
307 return;
308 if (buffer_id < 0) {
309 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
310 "invalid buffer_id=" << buffer_id;
311 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
312 return;
314 if (buffer_size < output_buffer_size_) {
315 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
316 "buffer too small for buffer_id=" << buffer_id;
317 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
318 return;
320 encoder_->UseOutputBitstreamBuffer(
321 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
324 void GpuVideoEncodeAccelerator::OnDestroy() {
325 DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
326 OnWillDestroyStub();
329 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
330 uint32 bitrate,
331 uint32 framerate) {
332 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
333 "bitrate=" << bitrate
334 << ", framerate=" << framerate;
335 if (!encoder_)
336 return;
337 encoder_->RequestEncodingParametersChange(bitrate, framerate);
340 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
341 int32 frame_id,
342 scoped_ptr<base::SharedMemory> shm) {
343 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
344 frame_id));
345 // Just let shm fall out of scope.
348 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
349 stub_->channel()->Send(message);
352 void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message* message,
353 bool succeeded) {
354 GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded);
355 Send(message);
358 } // namespace content