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/logging.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "build/build_config.h"
12 #include "content/common/gpu/gpu_channel.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "ipc/ipc_message_macros.h"
15 #include "media/base/limits.h"
16 #include "media/base/video_frame.h"
18 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
19 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
20 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
21 #include "content/common/gpu/media/android_video_encode_accelerator.h"
26 static bool MakeDecoderContextCurrent(
27 const base::WeakPtr<GpuCommandBufferStub> stub) {
29 DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
33 if (!stub->decoder()->MakeCurrent()) {
34 DLOG(ERROR) << "Failed to MakeCurrent()";
41 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id,
42 GpuCommandBufferStub* stub)
43 : host_route_id_(host_route_id),
45 input_format_(media::VideoFrame::UNKNOWN),
46 output_buffer_size_(0),
47 weak_this_factory_(this) {
48 stub_->AddDestructionObserver(this);
49 make_context_current_ =
50 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
53 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
54 // This class can only be self-deleted from OnWillDestroyStub(), which means
55 // the VEA has already been destroyed in there.
59 void GpuVideoEncodeAccelerator::Initialize(
60 media::VideoFrame::Format input_format,
61 const gfx::Size& input_visible_size,
62 media::VideoCodecProfile output_profile,
63 uint32 initial_bitrate,
64 IPC::Message* init_done_msg) {
65 DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): "
66 "input_format=" << input_format
67 << ", input_visible_size=" << input_visible_size.ToString()
68 << ", output_profile=" << output_profile
69 << ", initial_bitrate=" << initial_bitrate;
72 if (!stub_->channel()->AddRoute(host_route_id_, this)) {
73 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
74 "failed to add route";
75 SendCreateEncoderReply(init_done_msg, false);
79 if (input_visible_size.width() > media::limits::kMaxDimension ||
80 input_visible_size.height() > media::limits::kMaxDimension ||
81 input_visible_size.GetArea() > media::limits::kMaxCanvas) {
82 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
83 "input_visible_size " << input_visible_size.ToString()
85 SendCreateEncoderReply(init_done_msg, false);
92 << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
93 SendCreateEncoderReply(init_done_msg, false);
96 if (!encoder_->Initialize(input_format,
102 << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
103 SendCreateEncoderReply(init_done_msg, false);
106 input_format_ = input_format;
107 input_visible_size_ = input_visible_size;
108 SendCreateEncoderReply(init_done_msg, true);
111 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
113 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
114 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
115 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
116 OnUseOutputBitstreamBuffer)
118 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
119 OnRequestEncodingParametersChange)
120 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
121 IPC_MESSAGE_UNHANDLED(handled = false)
122 IPC_END_MESSAGE_MAP()
126 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
127 unsigned int input_count,
128 const gfx::Size& input_coded_size,
129 size_t output_buffer_size) {
130 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
131 host_route_id_, input_count, input_coded_size, output_buffer_size));
132 input_coded_size_ = input_coded_size;
133 output_buffer_size_ = output_buffer_size;
136 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
139 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
140 host_route_id_, bitstream_buffer_id, payload_size, key_frame));
143 void GpuVideoEncodeAccelerator::NotifyError(
144 media::VideoEncodeAccelerator::Error error) {
145 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
148 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
150 stub_->channel()->RemoveRoute(host_route_id_);
151 stub_->RemoveDestructionObserver(this);
154 encoder_.release()->Destroy();
160 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
161 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
162 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
164 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
165 profiles = V4L2VideoEncodeAccelerator::GetSupportedProfiles();
166 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
167 profiles = AndroidVideoEncodeAccelerator::GetSupportedProfiles();
170 // TODO(sheu): return platform-specific profiles.
174 void GpuVideoEncodeAccelerator::CreateEncoder() {
176 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
177 scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
181 encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass()));
182 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
183 encoder_.reset(new AndroidVideoEncodeAccelerator());
187 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
188 base::SharedMemoryHandle buffer_handle,
190 bool force_keyframe) {
191 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
192 << ", buffer_size=" << buffer_size
193 << ", force_keyframe=" << force_keyframe;
197 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
199 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
203 scoped_ptr<base::SharedMemory> shm(
204 new base::SharedMemory(buffer_handle, true));
205 if (!shm->Map(buffer_size)) {
206 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
207 "could not map frame_id=" << frame_id;
208 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
212 uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
213 scoped_refptr<media::VideoFrame> frame =
214 media::VideoFrame::WrapExternalPackedMemory(
217 gfx::Rect(input_visible_size_),
223 // It's turtles all the way down...
224 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
225 base::MessageLoopProxy::current(),
227 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
228 weak_this_factory_.GetWeakPtr(),
230 base::Passed(&shm))));
233 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
234 "could not create VideoFrame for frame_id=" << frame_id;
235 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
239 encoder_->Encode(frame, force_keyframe);
242 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
244 base::SharedMemoryHandle buffer_handle,
245 uint32 buffer_size) {
246 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
247 "buffer_id=" << buffer_id
248 << ", buffer_size=" << buffer_size;
252 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
253 "invalid buffer_id=" << buffer_id;
254 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
257 if (buffer_size < output_buffer_size_) {
258 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
259 "buffer too small for buffer_id=" << buffer_id;
260 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
263 encoder_->UseOutputBitstreamBuffer(
264 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
267 void GpuVideoEncodeAccelerator::OnDestroy() {
268 DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
272 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
275 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
276 "bitrate=" << bitrate
277 << ", framerate=" << framerate;
280 encoder_->RequestEncodingParametersChange(bitrate, framerate);
283 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
285 scoped_ptr<base::SharedMemory> shm) {
286 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
288 // Just let shm fall out of scope.
291 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
292 stub_->channel()->Send(message);
295 void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message* message,
297 GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded);
301 } // namespace content