Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / common / gpu / client / gpu_video_encode_accelerator_host.cc
blobb2b928650663a3dd3942763508258d76195dc548
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/client/gpu_video_encode_accelerator_host.h"
7 #include "base/logging.h"
8 #include "content/common/gpu/client/gpu_channel_host.h"
9 #include "content/common/gpu/gpu_messages.h"
10 #include "content/common/gpu/media/gpu_video_accelerator_util.h"
11 #include "media/base/video_frame.h"
13 namespace content {
15 #define NOTIFY_ERROR(error) \
16 PostNotifyError(error); \
17 DLOG(ERROR)
19 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
20 GpuChannelHost* channel,
21 CommandBufferProxyImpl* impl)
22 : channel_(channel),
23 encoder_route_id_(MSG_ROUTING_NONE),
24 client_(NULL),
25 impl_(impl),
26 next_frame_id_(0),
27 weak_this_factory_(this) {
28 DCHECK(channel_);
29 DCHECK(impl_);
30 impl_->AddDeletionObserver(this);
33 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
34 DCHECK(CalledOnValidThread());
35 if (channel_ && encoder_route_id_ != MSG_ROUTING_NONE)
36 channel_->RemoveRoute(encoder_route_id_);
37 if (impl_)
38 impl_->RemoveDeletionObserver(this);
41 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
42 const IPC::Message& message) {
43 bool handled = true;
44 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message)
45 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
46 OnRequireBitstreamBuffers)
47 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
48 OnNotifyInputDone)
49 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
50 OnBitstreamBufferReady)
51 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError,
52 OnNotifyError)
53 IPC_MESSAGE_UNHANDLED(handled = false)
54 IPC_END_MESSAGE_MAP()
55 DCHECK(handled);
56 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
57 // have been called above.
58 return handled;
61 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
62 DCHECK(CalledOnValidThread());
63 if (channel_) {
64 if (encoder_route_id_ != MSG_ROUTING_NONE)
65 channel_->RemoveRoute(encoder_route_id_);
66 channel_ = NULL;
68 NOTIFY_ERROR(kPlatformFailureError) << "OnChannelError()";
71 media::VideoEncodeAccelerator::SupportedProfiles
72 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
73 DCHECK(CalledOnValidThread());
74 if (!channel_)
75 return media::VideoEncodeAccelerator::SupportedProfiles();
76 return GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
77 channel_->gpu_info().video_encode_accelerator_supported_profiles);
80 bool GpuVideoEncodeAcceleratorHost::Initialize(
81 media::VideoPixelFormat input_format,
82 const gfx::Size& input_visible_size,
83 media::VideoCodecProfile output_profile,
84 uint32 initial_bitrate,
85 Client* client) {
86 DCHECK(CalledOnValidThread());
87 client_ = client;
88 if (!impl_) {
89 DLOG(ERROR) << "impl_ destroyed";
90 return false;
93 int32 route_id = channel_->GenerateRouteID();
94 channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr());
96 bool succeeded = false;
97 Send(new GpuCommandBufferMsg_CreateVideoEncoder(impl_->GetRouteID(),
98 input_format,
99 input_visible_size,
100 output_profile,
101 initial_bitrate,
102 route_id,
103 &succeeded));
104 if (!succeeded) {
105 DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed";
106 channel_->RemoveRoute(route_id);
107 return false;
109 encoder_route_id_ = route_id;
110 return true;
113 void GpuVideoEncodeAcceleratorHost::Encode(
114 const scoped_refptr<media::VideoFrame>& frame,
115 bool force_keyframe) {
116 DCHECK(CalledOnValidThread());
117 if (!channel_)
118 return;
120 if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) {
121 NOTIFY_ERROR(kPlatformFailureError) << "EncodeSharedMemory(): cannot "
122 "encode frame with invalid shared "
123 "memory handle";
124 return;
127 AcceleratedVideoEncoderMsg_Encode_Params params;
128 params.frame_id = next_frame_id_;
129 params.buffer_handle =
130 channel_->ShareToGpuProcess(frame->shared_memory_handle());
131 if (!base::SharedMemory::IsHandleValid(params.buffer_handle)) {
132 NOTIFY_ERROR(kPlatformFailureError) << "EncodeSharedMemory(): failed to "
133 "duplicate buffer handle for GPU "
134 "process";
135 return;
137 params.buffer_offset =
138 base::checked_cast<uint32_t>(frame->shared_memory_offset());
139 // We assume that planar frame data passed here is packed and contiguous.
140 base::CheckedNumeric<uint32_t> buffer_size = 0u;
141 for (size_t i = 0; i < media::VideoFrame::NumPlanes(frame->format()); ++i) {
142 // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
143 DCHECK_EQ(
144 reinterpret_cast<void*>(frame->data(i)),
145 reinterpret_cast<void*>((frame->data(0) + buffer_size.ValueOrDie())))
146 << "plane=" << i;
147 buffer_size +=
148 base::checked_cast<uint32_t>(frame->stride(i) * frame->rows(i));
150 params.buffer_size = buffer_size.ValueOrDie();
151 params.force_keyframe = force_keyframe;
153 Send(new AcceleratedVideoEncoderMsg_Encode(encoder_route_id_, params));
154 frame_map_[next_frame_id_] = frame;
156 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
157 next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF;
160 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
161 const media::BitstreamBuffer& buffer) {
162 DCHECK(CalledOnValidThread());
163 if (!channel_)
164 return;
166 base::SharedMemoryHandle handle =
167 channel_->ShareToGpuProcess(buffer.handle());
168 if (!base::SharedMemory::IsHandleValid(handle)) {
169 NOTIFY_ERROR(kPlatformFailureError)
170 << "UseOutputBitstreamBuffer(): failed to duplicate buffer handle "
171 "for GPU process: buffer.id()=" << buffer.id();
172 return;
174 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
175 encoder_route_id_, buffer.id(), handle, buffer.size()));
178 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
179 uint32 bitrate,
180 uint32 framerate) {
181 DCHECK(CalledOnValidThread());
182 if (!channel_)
183 return;
185 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
186 encoder_route_id_, bitrate, framerate));
189 void GpuVideoEncodeAcceleratorHost::Destroy() {
190 DCHECK(CalledOnValidThread());
191 if (channel_)
192 Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_));
193 client_ = NULL;
194 delete this;
197 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() {
198 DCHECK(CalledOnValidThread());
199 impl_ = NULL;
201 // The CommandBufferProxyImpl is going away; error out this VEA.
202 OnChannelError();
205 void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error) {
206 DCHECK(CalledOnValidThread());
207 DVLOG(2) << "PostNotifyError(): error=" << error;
208 // Post the error notification back to this thread, to avoid re-entrancy.
209 base::ThreadTaskRunnerHandle::Get()->PostTask(
210 FROM_HERE, base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError,
211 weak_this_factory_.GetWeakPtr(), error));
214 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
215 DCHECK(CalledOnValidThread());
216 uint32 message_type = message->type();
217 if (!channel_->Send(message)) {
218 NOTIFY_ERROR(kPlatformFailureError) << "Send(" << message_type
219 << ") failed";
223 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
224 uint32 input_count,
225 const gfx::Size& input_coded_size,
226 uint32 output_buffer_size) {
227 DCHECK(CalledOnValidThread());
228 DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
229 << ", input_coded_size=" << input_coded_size.ToString()
230 << ", output_buffer_size=" << output_buffer_size;
231 if (client_) {
232 client_->RequireBitstreamBuffers(
233 input_count, input_coded_size, output_buffer_size);
237 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) {
238 DCHECK(CalledOnValidThread());
239 DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id;
240 // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a
241 // frame can trigger a further encode to be kicked off and thus an .insert()
242 // back into the map, we separate the frame's dtor running from the .erase()
243 // running by holding on to the frame temporarily. This isn't "just
244 // theoretical" - Android's std::hash_map crashes if we don't do this.
245 scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id];
246 if (!frame_map_.erase(frame_id)) {
247 DLOG(ERROR) << "OnNotifyInputDone(): "
248 "invalid frame_id=" << frame_id;
249 // See OnNotifyError for why this needs to be the last thing in this
250 // function.
251 OnNotifyError(kPlatformFailureError);
252 return;
254 frame = NULL; // Not necessary but nice to be explicit; see fun-fact above.
257 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
258 int32 bitstream_buffer_id,
259 uint32 payload_size,
260 bool key_frame) {
261 DCHECK(CalledOnValidThread());
262 DVLOG(3) << "OnBitstreamBufferReady(): "
263 "bitstream_buffer_id=" << bitstream_buffer_id
264 << ", payload_size=" << payload_size
265 << ", key_frame=" << key_frame;
266 if (client_)
267 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
270 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
271 DCHECK(CalledOnValidThread());
272 DVLOG(2) << "OnNotifyError(): error=" << error;
273 if (!client_)
274 return;
275 weak_this_factory_.InvalidateWeakPtrs();
277 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
278 // last thing done on this stack!
279 media::VideoEncodeAccelerator::Client* client = NULL;
280 std::swap(client_, client);
281 client->NotifyError(error);
284 } // namespace content