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"
15 #define NOTIFY_ERROR(error) \
16 PostNotifyError(error); \
19 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
20 GpuChannelHost
* channel
,
21 CommandBufferProxyImpl
* impl
)
23 encoder_route_id_(MSG_ROUTING_NONE
),
27 weak_this_factory_(this) {
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_
);
38 impl_
->RemoveDeletionObserver(this);
41 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
42 const IPC::Message
& message
) {
44 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost
, message
)
45 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers
,
46 OnRequireBitstreamBuffers
)
47 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone
,
49 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady
,
50 OnBitstreamBufferReady
)
51 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError
,
53 IPC_MESSAGE_UNHANDLED(handled
= false)
56 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
57 // have been called above.
61 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
62 DCHECK(CalledOnValidThread());
64 if (encoder_route_id_
!= MSG_ROUTING_NONE
)
65 channel_
->RemoveRoute(encoder_route_id_
);
68 NOTIFY_ERROR(kPlatformFailureError
) << "OnChannelError()";
71 media::VideoEncodeAccelerator::SupportedProfiles
72 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
73 DCHECK(CalledOnValidThread());
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
,
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
) << "EncodeSharedMemory(): cannot "
122 "encode frame with invalid shared "
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 "
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.
144 reinterpret_cast<void*>(frame
->data(i
)),
145 reinterpret_cast<void*>((frame
->data(0) + buffer_size
.ValueOrDie())))
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());
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();
174 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
175 encoder_route_id_
, buffer
.id(), handle
, buffer
.size()));
178 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
181 DCHECK(CalledOnValidThread());
185 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
186 encoder_route_id_
, bitrate
, framerate
));
189 void GpuVideoEncodeAcceleratorHost::Destroy() {
190 DCHECK(CalledOnValidThread());
192 Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_
));
197 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() {
198 DCHECK(CalledOnValidThread());
201 // The CommandBufferProxyImpl is going away; error out this VEA.
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
223 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
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
;
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
251 OnNotifyError(kPlatformFailureError
);
254 frame
= NULL
; // Not necessary but nice to be explicit; see fun-fact above.
257 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
258 int32 bitstream_buffer_id
,
261 DCHECK(CalledOnValidThread());
262 DVLOG(3) << "OnBitstreamBufferReady(): "
263 "bitstream_buffer_id=" << bitstream_buffer_id
264 << ", payload_size=" << payload_size
265 << ", key_frame=" << key_frame
;
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
;
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