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/message_loop/message_loop_proxy.h"
12 #include "build/build_config.h"
13 #include "content/common/gpu/gpu_channel.h"
14 #include "content/common/gpu/gpu_messages.h"
15 #include "content/public/common/content_switches.h"
16 #include "ipc/ipc_message_macros.h"
17 #include "media/base/limits.h"
18 #include "media/base/video_frame.h"
20 #if defined(OS_CHROMEOS)
22 #if defined(ARCH_CPU_ARMEL) && defined(USE_X11)
23 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
24 #elif defined(ARCH_CPU_X86_FAMILY)
25 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
28 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
29 #include "content/common/gpu/media/android_video_encode_accelerator.h"
34 static bool MakeDecoderContextCurrent(
35 const base::WeakPtr
<GpuCommandBufferStub
> stub
) {
37 DLOG(ERROR
) << "Stub is gone; won't MakeCurrent().";
41 if (!stub
->decoder()->MakeCurrent()) {
42 DLOG(ERROR
) << "Failed to MakeCurrent()";
49 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id
,
50 GpuCommandBufferStub
* stub
)
51 : host_route_id_(host_route_id
),
53 input_format_(media::VideoFrame::UNKNOWN
),
54 output_buffer_size_(0),
55 weak_this_factory_(this) {
56 stub_
->AddDestructionObserver(this);
57 make_context_current_
=
58 base::Bind(&MakeDecoderContextCurrent
, stub_
->AsWeakPtr());
61 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
62 // This class can only be self-deleted from OnWillDestroyStub(), which means
63 // the VEA has already been destroyed in there.
67 void GpuVideoEncodeAccelerator::Initialize(
68 media::VideoFrame::Format input_format
,
69 const gfx::Size
& input_visible_size
,
70 media::VideoCodecProfile output_profile
,
71 uint32 initial_bitrate
,
72 IPC::Message
* init_done_msg
) {
73 DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): "
74 "input_format=" << input_format
75 << ", input_visible_size=" << input_visible_size
.ToString()
76 << ", output_profile=" << output_profile
77 << ", initial_bitrate=" << initial_bitrate
;
80 if (!stub_
->channel()->AddRoute(host_route_id_
, this)) {
81 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::Initialize(): "
82 "failed to add route";
83 SendCreateEncoderReply(init_done_msg
, false);
87 if (input_visible_size
.width() > media::limits::kMaxDimension
||
88 input_visible_size
.height() > media::limits::kMaxDimension
||
89 input_visible_size
.GetArea() > media::limits::kMaxCanvas
) {
90 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::Initialize(): "
91 "input_visible_size " << input_visible_size
.ToString()
93 SendCreateEncoderReply(init_done_msg
, false);
97 encoder_
= CreateEncoder();
100 << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
101 SendCreateEncoderReply(init_done_msg
, false);
104 if (!encoder_
->Initialize(input_format
,
110 << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
111 SendCreateEncoderReply(init_done_msg
, false);
114 input_format_
= input_format
;
115 input_visible_size_
= input_visible_size
;
116 SendCreateEncoderReply(init_done_msg
, true);
119 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message
& message
) {
121 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator
, message
)
122 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode
, OnEncode
)
123 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer
,
124 OnUseOutputBitstreamBuffer
)
126 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange
,
127 OnRequestEncodingParametersChange
)
128 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy
, OnDestroy
)
129 IPC_MESSAGE_UNHANDLED(handled
= false)
130 IPC_END_MESSAGE_MAP()
134 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
135 unsigned int input_count
,
136 const gfx::Size
& input_coded_size
,
137 size_t output_buffer_size
) {
138 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
139 host_route_id_
, input_count
, input_coded_size
, output_buffer_size
));
140 input_coded_size_
= input_coded_size
;
141 output_buffer_size_
= output_buffer_size
;
144 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id
,
147 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
148 host_route_id_
, bitstream_buffer_id
, payload_size
, key_frame
));
151 void GpuVideoEncodeAccelerator::NotifyError(
152 media::VideoEncodeAccelerator::Error error
) {
153 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_
, error
));
156 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
158 stub_
->channel()->RemoveRoute(host_route_id_
);
159 stub_
->RemoveDestructionObserver(this);
165 std::vector
<gpu::VideoEncodeAcceleratorSupportedProfile
>
166 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
167 scoped_ptr
<media::VideoEncodeAccelerator
> encoder
= CreateEncoder();
169 return std::vector
<gpu::VideoEncodeAcceleratorSupportedProfile
>();
170 return ConvertMediaToGpuProfiles(encoder
->GetSupportedProfiles());
173 std::vector
<gpu::VideoEncodeAcceleratorSupportedProfile
>
174 GpuVideoEncodeAccelerator::ConvertMediaToGpuProfiles(const std::vector
<
175 media::VideoEncodeAccelerator::SupportedProfile
>& media_profiles
) {
176 std::vector
<gpu::VideoEncodeAcceleratorSupportedProfile
> profiles
;
177 for (size_t i
= 0; i
< media_profiles
.size(); i
++) {
178 gpu::VideoEncodeAcceleratorSupportedProfile profile
;
180 static_cast<gpu::VideoCodecProfile
>(media_profiles
[i
].profile
);
181 profile
.max_resolution
= media_profiles
[i
].max_resolution
;
182 profile
.max_framerate_numerator
= media_profiles
[i
].max_framerate_numerator
;
183 profile
.max_framerate_denominator
=
184 media_profiles
[i
].max_framerate_denominator
;
185 profiles
.push_back(profile
);
190 scoped_ptr
<media::VideoEncodeAccelerator
>
191 GpuVideoEncodeAccelerator::CreateEncoder() {
192 scoped_ptr
<media::VideoEncodeAccelerator
> encoder
;
193 #if defined(OS_CHROMEOS)
194 #if defined(ARCH_CPU_ARMEL) && defined(USE_X11)
195 scoped_ptr
<V4L2Device
> device
= V4L2Device::Create(V4L2Device::kEncoder
);
197 encoder
.reset(new V4L2VideoEncodeAccelerator(device
.Pass()));
198 #elif defined(ARCH_CPU_X86_FAMILY)
199 const base::CommandLine
* cmd_line
= base::CommandLine::ForCurrentProcess();
200 if (!cmd_line
->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode
))
201 encoder
.reset(new VaapiVideoEncodeAccelerator());
203 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
204 encoder
.reset(new AndroidVideoEncodeAccelerator());
206 return encoder
.Pass();
209 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id
,
210 base::SharedMemoryHandle buffer_handle
,
212 bool force_keyframe
) {
213 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
214 << ", buffer_size=" << buffer_size
215 << ", force_keyframe=" << force_keyframe
;
219 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
221 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError
);
225 scoped_ptr
<base::SharedMemory
> shm(
226 new base::SharedMemory(buffer_handle
, true));
227 if (!shm
->Map(buffer_size
)) {
228 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::OnEncode(): "
229 "could not map frame_id=" << frame_id
;
230 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError
);
234 uint8
* shm_memory
= reinterpret_cast<uint8
*>(shm
->memory());
235 scoped_refptr
<media::VideoFrame
> frame
=
236 media::VideoFrame::WrapExternalPackedMemory(
239 gfx::Rect(input_visible_size_
),
245 // It's turtles all the way down...
246 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask
),
247 base::MessageLoopProxy::current(),
249 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished
,
250 weak_this_factory_
.GetWeakPtr(),
252 base::Passed(&shm
))));
255 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::OnEncode(): "
256 "could not create VideoFrame for frame_id=" << frame_id
;
257 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError
);
261 encoder_
->Encode(frame
, force_keyframe
);
264 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
266 base::SharedMemoryHandle buffer_handle
,
267 uint32 buffer_size
) {
268 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
269 "buffer_id=" << buffer_id
270 << ", buffer_size=" << buffer_size
;
274 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
275 "invalid buffer_id=" << buffer_id
;
276 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError
);
279 if (buffer_size
< output_buffer_size_
) {
280 DLOG(ERROR
) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
281 "buffer too small for buffer_id=" << buffer_id
;
282 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError
);
285 encoder_
->UseOutputBitstreamBuffer(
286 media::BitstreamBuffer(buffer_id
, buffer_handle
, buffer_size
));
289 void GpuVideoEncodeAccelerator::OnDestroy() {
290 DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
294 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
297 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
298 "bitrate=" << bitrate
299 << ", framerate=" << framerate
;
302 encoder_
->RequestEncodingParametersChange(bitrate
, framerate
);
305 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
307 scoped_ptr
<base::SharedMemory
> shm
) {
308 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_
,
310 // Just let shm fall out of scope.
313 void GpuVideoEncodeAccelerator::Send(IPC::Message
* message
) {
314 stub_
->channel()->Send(message
);
317 void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message
* message
,
319 GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message
, succeeded
);
323 } // namespace content