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 "base/message_loop/message_loop_proxy.h"
9 #include "content/common/gpu/client/gpu_channel_host.h"
10 #include "content/common/gpu/gpu_messages.h"
11 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
12 #include "media/base/video_frame.h"
16 #define NOTIFY_ERROR(error) \
17 PostNotifyError(error); \
20 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
21 GpuChannelHost* channel,
22 CommandBufferProxyImpl* impl)
24 encoder_route_id_(MSG_ROUTING_NONE),
28 weak_this_factory_(this) {
31 impl_->AddDeletionObserver(this);
34 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
35 DCHECK(CalledOnValidThread());
36 if (channel_ && encoder_route_id_ != MSG_ROUTING_NONE)
37 channel_->RemoveRoute(encoder_route_id_);
39 impl_->RemoveDeletionObserver(this);
42 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
43 const IPC::Message& message) {
45 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message)
46 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
47 OnRequireBitstreamBuffers)
48 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
50 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
51 OnBitstreamBufferReady)
52 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError,
54 IPC_MESSAGE_UNHANDLED(handled = false)
57 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
58 // have been called above.
62 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
63 DCHECK(CalledOnValidThread());
65 if (encoder_route_id_ != MSG_ROUTING_NONE)
66 channel_->RemoveRoute(encoder_route_id_);
69 NOTIFY_ERROR(kPlatformFailureError) << "OnChannelError()";
72 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
73 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
74 DCHECK(CalledOnValidThread());
76 return std::vector<media::VideoEncodeAccelerator::SupportedProfile>();
77 return channel_->gpu_info().video_encode_accelerator_supported_profiles;
80 bool GpuVideoEncodeAcceleratorHost::Initialize(
81 media::VideoFrame::Format input_format,
82 const gfx::Size& input_visible_size,
83 media::VideoCodecProfile output_profile,
84 uint32 initial_bitrate,
86 DCHECK(CalledOnValidThread());
89 DLOG(ERROR) << "impl_ destroyed";
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(),
105 DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed";
106 channel_->RemoveRoute(route_id);
109 encoder_route_id_ = route_id;
113 void GpuVideoEncodeAcceleratorHost::Encode(
114 const scoped_refptr<media::VideoFrame>& frame,
115 bool force_keyframe) {
116 DCHECK(CalledOnValidThread());
120 if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) {
121 NOTIFY_ERROR(kPlatformFailureError)
122 << "Encode(): cannot encode frame not backed by shared memory";
125 base::SharedMemoryHandle handle =
126 channel_->ShareToGpuProcess(frame->shared_memory_handle());
127 if (!base::SharedMemory::IsHandleValid(handle)) {
128 NOTIFY_ERROR(kPlatformFailureError)
129 << "Encode(): failed to duplicate buffer handle for GPU process";
133 // We assume that planar frame data passed here is packed and contiguous.
134 const size_t plane_count = media::VideoFrame::NumPlanes(frame->format());
135 size_t frame_size = 0;
136 for (size_t i = 0; i < plane_count; ++i) {
137 // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
138 DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)),
139 reinterpret_cast<void*>((frame->data(0) + frame_size)))
141 frame_size += frame->stride(i) * frame->rows(i);
144 Send(new AcceleratedVideoEncoderMsg_Encode(
145 encoder_route_id_, next_frame_id_, handle, frame_size, force_keyframe));
146 frame_map_[next_frame_id_] = frame;
148 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
149 next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF;
152 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
153 const media::BitstreamBuffer& buffer) {
154 DCHECK(CalledOnValidThread());
158 base::SharedMemoryHandle handle =
159 channel_->ShareToGpuProcess(buffer.handle());
160 if (!base::SharedMemory::IsHandleValid(handle)) {
161 NOTIFY_ERROR(kPlatformFailureError)
162 << "UseOutputBitstreamBuffer(): failed to duplicate buffer handle "
163 "for GPU process: buffer.id()=" << buffer.id();
166 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
167 encoder_route_id_, buffer.id(), handle, buffer.size()));
170 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
173 DCHECK(CalledOnValidThread());
177 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
178 encoder_route_id_, bitrate, framerate));
181 void GpuVideoEncodeAcceleratorHost::Destroy() {
182 DCHECK(CalledOnValidThread());
184 Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_));
189 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() {
190 DCHECK(CalledOnValidThread());
193 // The CommandBufferProxyImpl is going away; error out this VEA.
197 void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error) {
198 DCHECK(CalledOnValidThread());
199 DVLOG(2) << "PostNotifyError(): error=" << error;
200 // Post the error notification back to this thread, to avoid re-entrancy.
201 base::MessageLoopProxy::current()->PostTask(
203 base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError,
204 weak_this_factory_.GetWeakPtr(),
208 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
209 DCHECK(CalledOnValidThread());
210 uint32 message_type = message->type();
211 if (!channel_->Send(message)) {
212 NOTIFY_ERROR(kPlatformFailureError) << "Send(" << message_type
217 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
219 const gfx::Size& input_coded_size,
220 uint32 output_buffer_size) {
221 DCHECK(CalledOnValidThread());
222 DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
223 << ", input_coded_size=" << input_coded_size.ToString()
224 << ", output_buffer_size=" << output_buffer_size;
226 client_->RequireBitstreamBuffers(
227 input_count, input_coded_size, output_buffer_size);
231 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) {
232 DCHECK(CalledOnValidThread());
233 DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id;
234 // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a
235 // frame can trigger a further encode to be kicked off and thus an .insert()
236 // back into the map, we separate the frame's dtor running from the .erase()
237 // running by holding on to the frame temporarily. This isn't "just
238 // theoretical" - Android's std::hash_map crashes if we don't do this.
239 scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id];
240 if (!frame_map_.erase(frame_id)) {
241 DLOG(ERROR) << "OnNotifyInputDone(): "
242 "invalid frame_id=" << frame_id;
243 // See OnNotifyError for why this needs to be the last thing in this
245 OnNotifyError(kPlatformFailureError);
248 frame = NULL; // Not necessary but nice to be explicit; see fun-fact above.
251 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
252 int32 bitstream_buffer_id,
255 DCHECK(CalledOnValidThread());
256 DVLOG(3) << "OnBitstreamBufferReady(): "
257 "bitstream_buffer_id=" << bitstream_buffer_id
258 << ", payload_size=" << payload_size
259 << ", key_frame=" << key_frame;
261 client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
264 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
265 DCHECK(CalledOnValidThread());
266 DVLOG(2) << "OnNotifyError(): error=" << error;
269 weak_this_factory_.InvalidateWeakPtrs();
271 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
272 // last thing done on this stack!
273 media::VideoEncodeAccelerator::Client* client = NULL;
274 std::swap(client_, client);
275 client->NotifyError(error);
278 } // namespace content