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 ConvertGpuToMediaProfiles(
78 channel_
->gpu_info().video_encode_accelerator_supported_profiles
);
81 // Make sure the enum values of media::VideoCodecProfile and
82 // gpu::VideoCodecProfile match.
83 #define STATIC_ASSERT_ENUM_MATCH(name) \
85 media::name == static_cast<media::VideoCodecProfile>(gpu::name), \
86 #name " value must match in media and gpu.")
88 STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_UNKNOWN
);
89 STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MIN
);
90 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_BASELINE
);
91 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MAIN
);
92 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_EXTENDED
);
93 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH
);
94 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH10PROFILE
);
95 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH422PROFILE
);
96 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_HIGH444PREDICTIVEPROFILE
);
97 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEBASELINE
);
98 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_SCALABLEHIGH
);
99 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_STEREOHIGH
);
100 STATIC_ASSERT_ENUM_MATCH(H264PROFILE_MULTIVIEWHIGH
);
101 STATIC_ASSERT_ENUM_MATCH(VP8PROFILE_ANY
);
102 STATIC_ASSERT_ENUM_MATCH(VP9PROFILE_ANY
);
103 STATIC_ASSERT_ENUM_MATCH(VIDEO_CODEC_PROFILE_MAX
);
105 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
>
106 GpuVideoEncodeAcceleratorHost::ConvertGpuToMediaProfiles(const std::vector
<
107 gpu::VideoEncodeAcceleratorSupportedProfile
>& gpu_profiles
) {
108 std::vector
<media::VideoEncodeAccelerator::SupportedProfile
> profiles
;
109 for (size_t i
= 0; i
< gpu_profiles
.size(); i
++) {
110 media::VideoEncodeAccelerator::SupportedProfile profile
;
112 static_cast<media::VideoCodecProfile
>(gpu_profiles
[i
].profile
);
113 profile
.max_resolution
= gpu_profiles
[i
].max_resolution
;
114 profile
.max_framerate_numerator
= gpu_profiles
[i
].max_framerate_numerator
;
115 profile
.max_framerate_denominator
=
116 gpu_profiles
[i
].max_framerate_denominator
;
117 profiles
.push_back(profile
);
122 bool GpuVideoEncodeAcceleratorHost::Initialize(
123 media::VideoFrame::Format input_format
,
124 const gfx::Size
& input_visible_size
,
125 media::VideoCodecProfile output_profile
,
126 uint32 initial_bitrate
,
128 DCHECK(CalledOnValidThread());
131 DLOG(ERROR
) << "impl_ destroyed";
135 int32 route_id
= channel_
->GenerateRouteID();
136 channel_
->AddRoute(route_id
, weak_this_factory_
.GetWeakPtr());
138 bool succeeded
= false;
139 Send(new GpuCommandBufferMsg_CreateVideoEncoder(impl_
->GetRouteID(),
147 DLOG(ERROR
) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed";
148 channel_
->RemoveRoute(route_id
);
151 encoder_route_id_
= route_id
;
155 void GpuVideoEncodeAcceleratorHost::Encode(
156 const scoped_refptr
<media::VideoFrame
>& frame
,
157 bool force_keyframe
) {
158 DCHECK(CalledOnValidThread());
162 if (!base::SharedMemory::IsHandleValid(frame
->shared_memory_handle())) {
163 NOTIFY_ERROR(kPlatformFailureError
)
164 << "Encode(): cannot encode frame not backed by shared memory";
167 base::SharedMemoryHandle handle
=
168 channel_
->ShareToGpuProcess(frame
->shared_memory_handle());
169 if (!base::SharedMemory::IsHandleValid(handle
)) {
170 NOTIFY_ERROR(kPlatformFailureError
)
171 << "Encode(): failed to duplicate buffer handle for GPU process";
175 // We assume that planar frame data passed here is packed and contiguous.
176 const size_t plane_count
= media::VideoFrame::NumPlanes(frame
->format());
177 size_t frame_size
= 0;
178 for (size_t i
= 0; i
< plane_count
; ++i
) {
179 // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
180 DCHECK_EQ(reinterpret_cast<void*>(frame
->data(i
)),
181 reinterpret_cast<void*>((frame
->data(0) + frame_size
)))
183 frame_size
+= frame
->stride(i
) * frame
->rows(i
);
186 Send(new AcceleratedVideoEncoderMsg_Encode(
187 encoder_route_id_
, next_frame_id_
, handle
, frame
->shared_memory_offset(),
188 frame_size
, force_keyframe
));
189 frame_map_
[next_frame_id_
] = frame
;
191 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
192 next_frame_id_
= (next_frame_id_
+ 1) & 0x3FFFFFFF;
195 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
196 const media::BitstreamBuffer
& buffer
) {
197 DCHECK(CalledOnValidThread());
201 base::SharedMemoryHandle handle
=
202 channel_
->ShareToGpuProcess(buffer
.handle());
203 if (!base::SharedMemory::IsHandleValid(handle
)) {
204 NOTIFY_ERROR(kPlatformFailureError
)
205 << "UseOutputBitstreamBuffer(): failed to duplicate buffer handle "
206 "for GPU process: buffer.id()=" << buffer
.id();
209 Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
210 encoder_route_id_
, buffer
.id(), handle
, buffer
.size()));
213 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
216 DCHECK(CalledOnValidThread());
220 Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
221 encoder_route_id_
, bitrate
, framerate
));
224 void GpuVideoEncodeAcceleratorHost::Destroy() {
225 DCHECK(CalledOnValidThread());
227 Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_
));
232 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() {
233 DCHECK(CalledOnValidThread());
236 // The CommandBufferProxyImpl is going away; error out this VEA.
240 void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error
) {
241 DCHECK(CalledOnValidThread());
242 DVLOG(2) << "PostNotifyError(): error=" << error
;
243 // Post the error notification back to this thread, to avoid re-entrancy.
244 base::MessageLoopProxy::current()->PostTask(
246 base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError
,
247 weak_this_factory_
.GetWeakPtr(),
251 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message
* message
) {
252 DCHECK(CalledOnValidThread());
253 uint32 message_type
= message
->type();
254 if (!channel_
->Send(message
)) {
255 NOTIFY_ERROR(kPlatformFailureError
) << "Send(" << message_type
260 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
262 const gfx::Size
& input_coded_size
,
263 uint32 output_buffer_size
) {
264 DCHECK(CalledOnValidThread());
265 DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
266 << ", input_coded_size=" << input_coded_size
.ToString()
267 << ", output_buffer_size=" << output_buffer_size
;
269 client_
->RequireBitstreamBuffers(
270 input_count
, input_coded_size
, output_buffer_size
);
274 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id
) {
275 DCHECK(CalledOnValidThread());
276 DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id
;
277 // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a
278 // frame can trigger a further encode to be kicked off and thus an .insert()
279 // back into the map, we separate the frame's dtor running from the .erase()
280 // running by holding on to the frame temporarily. This isn't "just
281 // theoretical" - Android's std::hash_map crashes if we don't do this.
282 scoped_refptr
<media::VideoFrame
> frame
= frame_map_
[frame_id
];
283 if (!frame_map_
.erase(frame_id
)) {
284 DLOG(ERROR
) << "OnNotifyInputDone(): "
285 "invalid frame_id=" << frame_id
;
286 // See OnNotifyError for why this needs to be the last thing in this
288 OnNotifyError(kPlatformFailureError
);
291 frame
= NULL
; // Not necessary but nice to be explicit; see fun-fact above.
294 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
295 int32 bitstream_buffer_id
,
298 DCHECK(CalledOnValidThread());
299 DVLOG(3) << "OnBitstreamBufferReady(): "
300 "bitstream_buffer_id=" << bitstream_buffer_id
301 << ", payload_size=" << payload_size
302 << ", key_frame=" << key_frame
;
304 client_
->BitstreamBufferReady(bitstream_buffer_id
, payload_size
, key_frame
);
307 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error
) {
308 DCHECK(CalledOnValidThread());
309 DVLOG(2) << "OnNotifyError(): error=" << error
;
312 weak_this_factory_
.InvalidateWeakPtrs();
314 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
315 // last thing done on this stack!
316 media::VideoEncodeAccelerator::Client
* client
= NULL
;
317 std::swap(client_
, client
);
318 client
->NotifyError(error
);
321 } // namespace content