Revert of Support multiple video decoders and encoders (patchset #14 id:260001 of...
[chromium-blink-merge.git] / content / common / gpu / media / gpu_video_encode_accelerator.cc
blob639d1d8ae6af4cf4098825199dc4a0ae174c99e1
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"
26 #endif
28 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
29 #include "content/common/gpu/media/android_video_encode_accelerator.h"
30 #endif
32 namespace content {
34 static bool MakeDecoderContextCurrent(
35 const base::WeakPtr<GpuCommandBufferStub> stub) {
36 if (!stub) {
37 DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
38 return false;
41 if (!stub->decoder()->MakeCurrent()) {
42 DLOG(ERROR) << "Failed to MakeCurrent()";
43 return false;
46 return true;
49 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id,
50 GpuCommandBufferStub* stub)
51 : host_route_id_(host_route_id),
52 stub_(stub),
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.
64 DCHECK(!encoder_);
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;
78 DCHECK(!encoder_);
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);
84 return;
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()
92 << " too large";
93 SendCreateEncoderReply(init_done_msg, false);
94 return;
97 encoder_ = CreateEncoder();
98 if (!encoder_) {
99 DLOG(ERROR)
100 << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
101 SendCreateEncoderReply(init_done_msg, false);
102 return;
104 if (!encoder_->Initialize(input_format,
105 input_visible_size,
106 output_profile,
107 initial_bitrate,
108 this)) {
109 DLOG(ERROR)
110 << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
111 SendCreateEncoderReply(init_done_msg, false);
112 return;
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) {
120 bool handled = true;
121 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
122 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
123 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
124 OnUseOutputBitstreamBuffer)
125 IPC_MESSAGE_HANDLER(
126 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
127 OnRequestEncodingParametersChange)
128 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
129 IPC_MESSAGE_UNHANDLED(handled = false)
130 IPC_END_MESSAGE_MAP()
131 return handled;
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,
145 size_t payload_size,
146 bool key_frame) {
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() {
157 DCHECK(stub_);
158 stub_->channel()->RemoveRoute(host_route_id_);
159 stub_->RemoveDestructionObserver(this);
160 encoder_.reset();
161 delete this;
164 // static
165 std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
166 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
167 scoped_ptr<media::VideoEncodeAccelerator> encoder = CreateEncoder();
168 if (!encoder)
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;
179 profile.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);
187 return profiles;
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);
196 if (device)
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());
202 #endif
203 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
204 encoder.reset(new AndroidVideoEncodeAccelerator());
205 #endif
206 return encoder.Pass();
209 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
210 base::SharedMemoryHandle buffer_handle,
211 uint32 buffer_size,
212 bool force_keyframe) {
213 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
214 << ", buffer_size=" << buffer_size
215 << ", force_keyframe=" << force_keyframe;
216 if (!encoder_)
217 return;
218 if (frame_id < 0) {
219 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
220 << frame_id;
221 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
222 return;
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);
231 return;
234 uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
235 scoped_refptr<media::VideoFrame> frame =
236 media::VideoFrame::WrapExternalPackedMemory(
237 input_format_,
238 input_coded_size_,
239 gfx::Rect(input_visible_size_),
240 input_visible_size_,
241 shm_memory,
242 buffer_size,
243 buffer_handle,
244 base::TimeDelta(),
245 // It's turtles all the way down...
246 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
247 base::MessageLoopProxy::current(),
248 FROM_HERE,
249 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
250 weak_this_factory_.GetWeakPtr(),
251 frame_id,
252 base::Passed(&shm))));
254 if (!frame.get()) {
255 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
256 "could not create VideoFrame for frame_id=" << frame_id;
257 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
258 return;
261 encoder_->Encode(frame, force_keyframe);
264 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
265 int32 buffer_id,
266 base::SharedMemoryHandle buffer_handle,
267 uint32 buffer_size) {
268 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
269 "buffer_id=" << buffer_id
270 << ", buffer_size=" << buffer_size;
271 if (!encoder_)
272 return;
273 if (buffer_id < 0) {
274 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
275 "invalid buffer_id=" << buffer_id;
276 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
277 return;
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);
283 return;
285 encoder_->UseOutputBitstreamBuffer(
286 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
289 void GpuVideoEncodeAccelerator::OnDestroy() {
290 DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
291 OnWillDestroyStub();
294 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
295 uint32 bitrate,
296 uint32 framerate) {
297 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
298 "bitrate=" << bitrate
299 << ", framerate=" << framerate;
300 if (!encoder_)
301 return;
302 encoder_->RequestEncodingParametersChange(bitrate, framerate);
305 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
306 int32 frame_id,
307 scoped_ptr<base::SharedMemory> shm) {
308 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
309 frame_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,
318 bool succeeded) {
319 GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded);
320 Send(message);
323 } // namespace content