Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / media / gpu_video_encode_accelerator.cc
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.
4
5 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
6
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"
19
20 #if defined(OS_CHROMEOS) && defined(USE_X11)
21
22 #if defined(ARCH_CPU_ARMEL)
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 #include "ui/gfx/x/x11_types.h"
27 #endif
28
29 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
30 #include "content/common/gpu/media/android_video_encode_accelerator.h"
31 #endif
32
33 namespace content {
34
35 static bool MakeDecoderContextCurrent(
36     const base::WeakPtr<GpuCommandBufferStub> stub) {
37   if (!stub) {
38     DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
39     return false;
40   }
41
42   if (!stub->decoder()->MakeCurrent()) {
43     DLOG(ERROR) << "Failed to MakeCurrent()";
44     return false;
45   }
46
47   return true;
48 }
49
50 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id,
51                                                      GpuCommandBufferStub* stub)
52     : host_route_id_(host_route_id),
53       stub_(stub),
54       input_format_(media::VideoFrame::UNKNOWN),
55       output_buffer_size_(0),
56       weak_this_factory_(this) {
57   stub_->AddDestructionObserver(this);
58   make_context_current_ =
59       base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
60 }
61
62 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
63   // This class can only be self-deleted from OnWillDestroyStub(), which means
64   // the VEA has already been destroyed in there.
65   DCHECK(!encoder_);
66 }
67
68 void GpuVideoEncodeAccelerator::Initialize(
69     media::VideoFrame::Format input_format,
70     const gfx::Size& input_visible_size,
71     media::VideoCodecProfile output_profile,
72     uint32 initial_bitrate,
73     IPC::Message* init_done_msg) {
74   DVLOG(2) << "GpuVideoEncodeAccelerator::Initialize(): "
75               "input_format=" << input_format
76            << ", input_visible_size=" << input_visible_size.ToString()
77            << ", output_profile=" << output_profile
78            << ", initial_bitrate=" << initial_bitrate;
79   DCHECK(!encoder_);
80
81   if (!stub_->channel()->AddRoute(host_route_id_, this)) {
82     DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
83                    "failed to add route";
84     SendCreateEncoderReply(init_done_msg, false);
85     return;
86   }
87
88   if (input_visible_size.width() > media::limits::kMaxDimension ||
89       input_visible_size.height() > media::limits::kMaxDimension ||
90       input_visible_size.GetArea() > media::limits::kMaxCanvas) {
91     DLOG(ERROR) << "GpuVideoEncodeAccelerator::Initialize(): "
92                    "input_visible_size " << input_visible_size.ToString()
93                 << " too large";
94     SendCreateEncoderReply(init_done_msg, false);
95     return;
96   }
97
98   encoder_ = CreateEncoder();
99   if (!encoder_) {
100     DLOG(ERROR)
101         << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
102     SendCreateEncoderReply(init_done_msg, false);
103     return;
104   }
105   if (!encoder_->Initialize(input_format,
106                             input_visible_size,
107                             output_profile,
108                             initial_bitrate,
109                             this)) {
110     DLOG(ERROR)
111         << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
112     SendCreateEncoderReply(init_done_msg, false);
113     return;
114   }
115   input_format_ = input_format;
116   input_visible_size_ = input_visible_size;
117   SendCreateEncoderReply(init_done_msg, true);
118 }
119
120 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
121   bool handled = true;
122   IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
123     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
124     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
125                         OnUseOutputBitstreamBuffer)
126     IPC_MESSAGE_HANDLER(
127         AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
128         OnRequestEncodingParametersChange)
129     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
130     IPC_MESSAGE_UNHANDLED(handled = false)
131   IPC_END_MESSAGE_MAP()
132   return handled;
133 }
134
135 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
136     unsigned int input_count,
137     const gfx::Size& input_coded_size,
138     size_t output_buffer_size) {
139   Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
140       host_route_id_, input_count, input_coded_size, output_buffer_size));
141   input_coded_size_ = input_coded_size;
142   output_buffer_size_ = output_buffer_size;
143 }
144
145 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
146                                                      size_t payload_size,
147                                                      bool key_frame) {
148   Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
149       host_route_id_, bitstream_buffer_id, payload_size, key_frame));
150 }
151
152 void GpuVideoEncodeAccelerator::NotifyError(
153     media::VideoEncodeAccelerator::Error error) {
154   Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
155 }
156
157 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
158   DCHECK(stub_);
159   stub_->channel()->RemoveRoute(host_route_id_);
160   stub_->RemoveDestructionObserver(this);
161   encoder_.reset();
162   delete this;
163 }
164
165 // static
166 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
167 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
168 #if defined(OS_CHROMEOS) && defined(USE_X11) && defined(ARCH_CPU_ARMEL)
169   // This is a work-around for M39 because the video device is not ready at
170   // boot.
171   // TODO(wuchengli): remove this after http://crbug.com/418762 is fixed.
172   return V4L2VideoEncodeAccelerator::GetSupportedProfilesStatic();
173 #endif
174   scoped_ptr<media::VideoEncodeAccelerator> encoder = CreateEncoder();
175   if (!encoder)
176     return std::vector<media::VideoEncodeAccelerator::SupportedProfile>();
177   return encoder->GetSupportedProfiles();
178 }
179
180 scoped_ptr<media::VideoEncodeAccelerator>
181 GpuVideoEncodeAccelerator::CreateEncoder() {
182   scoped_ptr<media::VideoEncodeAccelerator> encoder;
183 #if defined(OS_CHROMEOS) && defined(USE_X11)
184 #if defined(ARCH_CPU_ARMEL)
185   scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
186   if (device)
187     encoder.reset(new V4L2VideoEncodeAccelerator(device.Pass()));
188 #elif defined(ARCH_CPU_X86_FAMILY)
189   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
190   if (!cmd_line->HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode))
191     encoder.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay()));
192 #endif
193 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
194   encoder.reset(new AndroidVideoEncodeAccelerator());
195 #endif
196   return encoder.Pass();
197 }
198
199 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
200                                          base::SharedMemoryHandle buffer_handle,
201                                          uint32 buffer_size,
202                                          bool force_keyframe) {
203   DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
204            << ", buffer_size=" << buffer_size
205            << ", force_keyframe=" << force_keyframe;
206   if (!encoder_)
207     return;
208   if (frame_id < 0) {
209     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
210                 << frame_id;
211     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
212     return;
213   }
214
215   scoped_ptr<base::SharedMemory> shm(
216       new base::SharedMemory(buffer_handle, true));
217   if (!shm->Map(buffer_size)) {
218     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
219                    "could not map frame_id=" << frame_id;
220     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
221     return;
222   }
223
224   uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
225   scoped_refptr<media::VideoFrame> frame =
226       media::VideoFrame::WrapExternalPackedMemory(
227           input_format_,
228           input_coded_size_,
229           gfx::Rect(input_visible_size_),
230           input_visible_size_,
231           shm_memory,
232           buffer_size,
233           buffer_handle,
234           base::TimeDelta(),
235           // It's turtles all the way down...
236           base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
237                      base::MessageLoopProxy::current(),
238                      FROM_HERE,
239                      base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
240                                 weak_this_factory_.GetWeakPtr(),
241                                 frame_id,
242                                 base::Passed(&shm))));
243
244   if (!frame.get()) {
245     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
246                    "could not create VideoFrame for frame_id=" << frame_id;
247     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
248     return;
249   }
250
251   encoder_->Encode(frame, force_keyframe);
252 }
253
254 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
255     int32 buffer_id,
256     base::SharedMemoryHandle buffer_handle,
257     uint32 buffer_size) {
258   DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
259               "buffer_id=" << buffer_id
260            << ", buffer_size=" << buffer_size;
261   if (!encoder_)
262     return;
263   if (buffer_id < 0) {
264     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
265                    "invalid buffer_id=" << buffer_id;
266     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
267     return;
268   }
269   if (buffer_size < output_buffer_size_) {
270     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
271                    "buffer too small for buffer_id=" << buffer_id;
272     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
273     return;
274   }
275   encoder_->UseOutputBitstreamBuffer(
276       media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
277 }
278
279 void GpuVideoEncodeAccelerator::OnDestroy() {
280   DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
281   OnWillDestroyStub();
282 }
283
284 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
285     uint32 bitrate,
286     uint32 framerate) {
287   DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
288               "bitrate=" << bitrate
289            << ", framerate=" << framerate;
290   if (!encoder_)
291     return;
292   encoder_->RequestEncodingParametersChange(bitrate, framerate);
293 }
294
295 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
296     int32 frame_id,
297     scoped_ptr<base::SharedMemory> shm) {
298   Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
299                                                           frame_id));
300   // Just let shm fall out of scope.
301 }
302
303 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
304   stub_->channel()->Send(message);
305 }
306
307 void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message* message,
308                                                        bool succeeded) {
309   GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded);
310   Send(message);
311 }
312
313 }  // namespace content