Upstream version 7.36.149.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/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"
17
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"
22 #endif
23
24 namespace content {
25
26 static bool MakeDecoderContextCurrent(
27     const base::WeakPtr<GpuCommandBufferStub> stub) {
28   if (!stub) {
29     DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
30     return false;
31   }
32
33   if (!stub->decoder()->MakeCurrent()) {
34     DLOG(ERROR) << "Failed to MakeCurrent()";
35     return false;
36   }
37
38   return true;
39 }
40
41 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(int32 host_route_id,
42                                                      GpuCommandBufferStub* stub)
43     : host_route_id_(host_route_id),
44       stub_(stub),
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());
51 }
52
53 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
54   // This class can only be self-deleted from OnWillDestroyStub(), which means
55   // the VEA has already been destroyed in there.
56   DCHECK(!encoder_);
57 }
58
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;
70   DCHECK(!encoder_);
71
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);
76     return;
77   }
78
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()
84                 << " too large";
85     SendCreateEncoderReply(init_done_msg, false);
86     return;
87   }
88
89   CreateEncoder();
90   if (!encoder_) {
91     DLOG(ERROR)
92         << "GpuVideoEncodeAccelerator::Initialize(): VEA creation failed";
93     SendCreateEncoderReply(init_done_msg, false);
94     return;
95   }
96   if (!encoder_->Initialize(input_format,
97                             input_visible_size,
98                             output_profile,
99                             initial_bitrate,
100                             this)) {
101     DLOG(ERROR)
102         << "GpuVideoEncodeAccelerator::Initialize(): VEA initialization failed";
103     SendCreateEncoderReply(init_done_msg, false);
104     return;
105   }
106   input_format_ = input_format;
107   input_visible_size_ = input_visible_size;
108   SendCreateEncoderReply(init_done_msg, true);
109 }
110
111 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
112   bool handled = true;
113   IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
114     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
115     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
116                         OnUseOutputBitstreamBuffer)
117     IPC_MESSAGE_HANDLER(
118         AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
119         OnRequestEncodingParametersChange)
120     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Destroy, OnDestroy)
121     IPC_MESSAGE_UNHANDLED(handled = false)
122   IPC_END_MESSAGE_MAP()
123   return handled;
124 }
125
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;
134 }
135
136 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
137                                                      size_t payload_size,
138                                                      bool key_frame) {
139   Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
140       host_route_id_, bitstream_buffer_id, payload_size, key_frame));
141 }
142
143 void GpuVideoEncodeAccelerator::NotifyError(
144     media::VideoEncodeAccelerator::Error error) {
145   Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
146 }
147
148 void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
149   DCHECK(stub_);
150   stub_->channel()->RemoveRoute(host_route_id_);
151   stub_->RemoveDestructionObserver(this);
152
153   if (encoder_)
154     encoder_.release()->Destroy();
155
156   delete this;
157 }
158
159 // static
160 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
161 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
162   std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
163
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();
168 #endif
169
170   // TODO(sheu): return platform-specific profiles.
171   return profiles;
172 }
173
174 void GpuVideoEncodeAccelerator::CreateEncoder() {
175   DCHECK(!encoder_);
176 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
177   scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
178   if (!device.get())
179     return;
180
181   encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass()));
182 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
183   encoder_.reset(new AndroidVideoEncodeAccelerator());
184 #endif
185 }
186
187 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
188                                          base::SharedMemoryHandle buffer_handle,
189                                          uint32 buffer_size,
190                                          bool force_keyframe) {
191   DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
192            << ", buffer_size=" << buffer_size
193            << ", force_keyframe=" << force_keyframe;
194   if (!encoder_)
195     return;
196   if (frame_id < 0) {
197     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
198                 << frame_id;
199     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
200     return;
201   }
202
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);
209     return;
210   }
211
212   uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
213   scoped_refptr<media::VideoFrame> frame =
214       media::VideoFrame::WrapExternalPackedMemory(
215           input_format_,
216           input_coded_size_,
217           gfx::Rect(input_visible_size_),
218           input_visible_size_,
219           shm_memory,
220           buffer_size,
221           buffer_handle,
222           base::TimeDelta(),
223           // It's turtles all the way down...
224           base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
225                      base::MessageLoopProxy::current(),
226                      FROM_HERE,
227                      base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
228                                 weak_this_factory_.GetWeakPtr(),
229                                 frame_id,
230                                 base::Passed(&shm))));
231
232   if (!frame) {
233     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
234                    "could not create VideoFrame for frame_id=" << frame_id;
235     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
236     return;
237   }
238
239   encoder_->Encode(frame, force_keyframe);
240 }
241
242 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
243     int32 buffer_id,
244     base::SharedMemoryHandle buffer_handle,
245     uint32 buffer_size) {
246   DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
247               "buffer_id=" << buffer_id
248            << ", buffer_size=" << buffer_size;
249   if (!encoder_)
250     return;
251   if (buffer_id < 0) {
252     DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
253                    "invalid buffer_id=" << buffer_id;
254     NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
255     return;
256   }
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);
261     return;
262   }
263   encoder_->UseOutputBitstreamBuffer(
264       media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
265 }
266
267 void GpuVideoEncodeAccelerator::OnDestroy() {
268   DVLOG(2) << "GpuVideoEncodeAccelerator::OnDestroy()";
269   OnWillDestroyStub();
270 }
271
272 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
273     uint32 bitrate,
274     uint32 framerate) {
275   DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
276               "bitrate=" << bitrate
277            << ", framerate=" << framerate;
278   if (!encoder_)
279     return;
280   encoder_->RequestEncodingParametersChange(bitrate, framerate);
281 }
282
283 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
284     int32 frame_id,
285     scoped_ptr<base::SharedMemory> shm) {
286   Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
287                                                           frame_id));
288   // Just let shm fall out of scope.
289 }
290
291 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
292   stub_->channel()->Send(message);
293 }
294
295 void GpuVideoEncodeAccelerator::SendCreateEncoderReply(IPC::Message* message,
296                                                        bool succeeded) {
297   GpuCommandBufferMsg_CreateVideoEncoder::WriteReplyParams(message, succeeded);
298   Send(message);
299 }
300
301 }  // namespace content