Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / client / gpu_video_encode_accelerator_host.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/client/gpu_video_encode_accelerator_host.h"
6
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "content/common/gpu/client/gpu_channel_host.h"
10 #include "content/common/gpu/gpu_messages.h"
11 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
12 #include "media/base/video_frame.h"
13
14 namespace content {
15
16 #define NOTIFY_ERROR(error) \
17   PostNotifyError(error);   \
18   DLOG(ERROR)
19
20 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
21     GpuChannelHost* channel,
22     CommandBufferProxyImpl* impl)
23     : channel_(channel),
24       encoder_route_id_(MSG_ROUTING_NONE),
25       client_(NULL),
26       impl_(impl),
27       next_frame_id_(0),
28       weak_this_factory_(this) {
29   DCHECK(channel_);
30   DCHECK(impl_);
31   impl_->AddDeletionObserver(this);
32 }
33
34 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
35   DCHECK(CalledOnValidThread());
36   if (channel_ && encoder_route_id_ != MSG_ROUTING_NONE)
37     channel_->RemoveRoute(encoder_route_id_);
38   if (impl_)
39     impl_->RemoveDeletionObserver(this);
40 }
41
42 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
43     const IPC::Message& message) {
44   bool handled = true;
45   IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message)
46     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
47                         OnRequireBitstreamBuffers)
48     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
49                         OnNotifyInputDone)
50     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
51                         OnBitstreamBufferReady)
52     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError,
53                         OnNotifyError)
54     IPC_MESSAGE_UNHANDLED(handled = false)
55   IPC_END_MESSAGE_MAP()
56   DCHECK(handled);
57   // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
58   // have been called above.
59   return handled;
60 }
61
62 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
63   DCHECK(CalledOnValidThread());
64   if (channel_) {
65     if (encoder_route_id_ != MSG_ROUTING_NONE)
66       channel_->RemoveRoute(encoder_route_id_);
67     channel_ = NULL;
68   }
69   NOTIFY_ERROR(kPlatformFailureError) << "OnChannelError()";
70 }
71
72 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
73 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
74   DCHECK(CalledOnValidThread());
75   if (!channel_)
76     return std::vector<media::VideoEncodeAccelerator::SupportedProfile>();
77   return channel_->gpu_info().video_encode_accelerator_supported_profiles;
78 }
79
80 bool GpuVideoEncodeAcceleratorHost::Initialize(
81     media::VideoFrame::Format input_format,
82     const gfx::Size& input_visible_size,
83     media::VideoCodecProfile output_profile,
84     uint32 initial_bitrate,
85     Client* client) {
86   DCHECK(CalledOnValidThread());
87   client_ = client;
88   if (!impl_) {
89     DLOG(ERROR) << "impl_ destroyed";
90     return false;
91   }
92
93   int32 route_id = channel_->GenerateRouteID();
94   channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr());
95
96   bool succeeded = false;
97   Send(new GpuCommandBufferMsg_CreateVideoEncoder(impl_->GetRouteID(),
98                                                   input_format,
99                                                   input_visible_size,
100                                                   output_profile,
101                                                   initial_bitrate,
102                                                   route_id,
103                                                   &succeeded));
104   if (!succeeded) {
105     DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoEncoder()) failed";
106     channel_->RemoveRoute(route_id);
107     return false;
108   }
109   encoder_route_id_ = route_id;
110   return true;
111 }
112
113 void GpuVideoEncodeAcceleratorHost::Encode(
114     const scoped_refptr<media::VideoFrame>& frame,
115     bool force_keyframe) {
116   DCHECK(CalledOnValidThread());
117   if (!channel_)
118     return;
119
120   if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) {
121     NOTIFY_ERROR(kPlatformFailureError)
122         << "Encode(): cannot encode frame not backed by shared memory";
123     return;
124   }
125   base::SharedMemoryHandle handle =
126       channel_->ShareToGpuProcess(frame->shared_memory_handle());
127   if (!base::SharedMemory::IsHandleValid(handle)) {
128     NOTIFY_ERROR(kPlatformFailureError)
129         << "Encode(): failed to duplicate buffer handle for GPU process";
130     return;
131   }
132
133   // We assume that planar frame data passed here is packed and contiguous.
134   const size_t plane_count = media::VideoFrame::NumPlanes(frame->format());
135   size_t frame_size = 0;
136   for (size_t i = 0; i < plane_count; ++i) {
137     // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
138     DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)),
139               reinterpret_cast<void*>((frame->data(0) + frame_size)))
140         << "plane=" << i;
141     frame_size += frame->stride(i) * frame->rows(i);
142   }
143
144   Send(new AcceleratedVideoEncoderMsg_Encode(
145       encoder_route_id_, next_frame_id_, handle, frame_size, force_keyframe));
146   frame_map_[next_frame_id_] = frame;
147
148   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
149   next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF;
150 }
151
152 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
153     const media::BitstreamBuffer& buffer) {
154   DCHECK(CalledOnValidThread());
155   if (!channel_)
156     return;
157
158   base::SharedMemoryHandle handle =
159       channel_->ShareToGpuProcess(buffer.handle());
160   if (!base::SharedMemory::IsHandleValid(handle)) {
161     NOTIFY_ERROR(kPlatformFailureError)
162         << "UseOutputBitstreamBuffer(): failed to duplicate buffer handle "
163            "for GPU process: buffer.id()=" << buffer.id();
164     return;
165   }
166   Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
167       encoder_route_id_, buffer.id(), handle, buffer.size()));
168 }
169
170 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
171     uint32 bitrate,
172     uint32 framerate) {
173   DCHECK(CalledOnValidThread());
174   if (!channel_)
175     return;
176
177   Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
178       encoder_route_id_, bitrate, framerate));
179 }
180
181 void GpuVideoEncodeAcceleratorHost::Destroy() {
182   DCHECK(CalledOnValidThread());
183   if (channel_)
184     Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_));
185   client_ = NULL;
186   delete this;
187 }
188
189 void GpuVideoEncodeAcceleratorHost::OnWillDeleteImpl() {
190   DCHECK(CalledOnValidThread());
191   impl_ = NULL;
192
193   // The CommandBufferProxyImpl is going away; error out this VEA.
194   OnChannelError();
195 }
196
197 void GpuVideoEncodeAcceleratorHost::PostNotifyError(Error error) {
198   DCHECK(CalledOnValidThread());
199   DVLOG(2) << "PostNotifyError(): error=" << error;
200   // Post the error notification back to this thread, to avoid re-entrancy.
201   base::MessageLoopProxy::current()->PostTask(
202       FROM_HERE,
203       base::Bind(&GpuVideoEncodeAcceleratorHost::OnNotifyError,
204                  weak_this_factory_.GetWeakPtr(),
205                  error));
206 }
207
208 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
209   DCHECK(CalledOnValidThread());
210   uint32 message_type = message->type();
211   if (!channel_->Send(message)) {
212     NOTIFY_ERROR(kPlatformFailureError) << "Send(" << message_type
213                                         << ") failed";
214   }
215 }
216
217 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
218     uint32 input_count,
219     const gfx::Size& input_coded_size,
220     uint32 output_buffer_size) {
221   DCHECK(CalledOnValidThread());
222   DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
223            << ", input_coded_size=" << input_coded_size.ToString()
224            << ", output_buffer_size=" << output_buffer_size;
225   if (client_) {
226     client_->RequireBitstreamBuffers(
227         input_count, input_coded_size, output_buffer_size);
228   }
229 }
230
231 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) {
232   DCHECK(CalledOnValidThread());
233   DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id;
234   // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a
235   // frame can trigger a further encode to be kicked off and thus an .insert()
236   // back into the map, we separate the frame's dtor running from the .erase()
237   // running by holding on to the frame temporarily.  This isn't "just
238   // theoretical" - Android's std::hash_map crashes if we don't do this.
239   scoped_refptr<media::VideoFrame> frame = frame_map_[frame_id];
240   if (!frame_map_.erase(frame_id)) {
241     DLOG(ERROR) << "OnNotifyInputDone(): "
242                    "invalid frame_id=" << frame_id;
243     // See OnNotifyError for why this needs to be the last thing in this
244     // function.
245     OnNotifyError(kPlatformFailureError);
246     return;
247   }
248   frame = NULL;  // Not necessary but nice to be explicit; see fun-fact above.
249 }
250
251 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
252     int32 bitstream_buffer_id,
253     uint32 payload_size,
254     bool key_frame) {
255   DCHECK(CalledOnValidThread());
256   DVLOG(3) << "OnBitstreamBufferReady(): "
257               "bitstream_buffer_id=" << bitstream_buffer_id
258            << ", payload_size=" << payload_size
259            << ", key_frame=" << key_frame;
260   if (client_)
261     client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
262 }
263
264 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
265   DCHECK(CalledOnValidThread());
266   DVLOG(2) << "OnNotifyError(): error=" << error;
267   if (!client_)
268     return;
269   weak_this_factory_.InvalidateWeakPtrs();
270
271   // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
272   // last thing done on this stack!
273   media::VideoEncodeAccelerator::Client* client = NULL;
274   std::swap(client_, client);
275   client->NotifyError(error);
276 }
277
278 }  // namespace content