- add sources.
[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 GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
17     media::VideoEncodeAccelerator::Client* client,
18     const scoped_refptr<GpuChannelHost>& gpu_channel_host,
19     int32 route_id)
20     : client_(client),
21       client_ptr_factory_(client_),
22       channel_(gpu_channel_host),
23       route_id_(route_id),
24       next_frame_id_(0) {
25   channel_->AddRoute(route_id_, AsWeakPtr());
26 }
27
28 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
29   if (channel_)
30     channel_->RemoveRoute(route_id_);
31 }
32
33 // static
34 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
35 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
36   return GpuVideoEncodeAccelerator::GetSupportedProfiles();
37 }
38
39 bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
40     const IPC::Message& message) {
41   bool handled = true;
42   IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message)
43     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInitializeDone,
44                         OnNotifyInitializeDone)
45     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
46                         OnRequireBitstreamBuffers)
47     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
48                         OnNotifyInputDone)
49     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
50                         OnBitstreamBufferReady)
51     IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError,
52                         OnNotifyError)
53     IPC_MESSAGE_UNHANDLED(handled = false)
54   IPC_END_MESSAGE_MAP()
55   DCHECK(handled);
56   // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
57   // have been called above.
58   return handled;
59 }
60
61 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
62   DLOG(ERROR) << "OnChannelError()";
63   if (channel_) {
64     channel_->RemoveRoute(route_id_);
65     channel_ = NULL;
66   }
67   // See OnNotifyError for why this needs to be the last thing in this
68   // function.
69   OnNotifyError(kPlatformFailureError);
70 }
71
72 void GpuVideoEncodeAcceleratorHost::Initialize(
73     media::VideoFrame::Format input_format,
74     const gfx::Size& input_visible_size,
75     media::VideoCodecProfile output_profile,
76     uint32 initial_bitrate) {
77   Send(new AcceleratedVideoEncoderMsg_Initialize(route_id_,
78                                                  input_format,
79                                                  input_visible_size,
80                                                  output_profile,
81                                                  initial_bitrate));
82 }
83
84 void GpuVideoEncodeAcceleratorHost::Encode(
85     const scoped_refptr<media::VideoFrame>& frame,
86     bool force_keyframe) {
87   if (!channel_)
88     return;
89   if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) {
90     DLOG(ERROR) << "Encode(): cannot encode frame not backed by shared memory";
91     NotifyError(kPlatformFailureError);
92     return;
93   }
94   base::SharedMemoryHandle handle =
95       channel_->ShareToGpuProcess(frame->shared_memory_handle());
96   if (!base::SharedMemory::IsHandleValid(handle)) {
97     DLOG(ERROR) << "Encode(): failed to duplicate buffer handle for GPU "
98                    "process";
99     NotifyError(kPlatformFailureError);
100     return;
101   }
102
103   // We assume that planar frame data passed here is packed and contiguous.
104   const size_t plane_count = media::VideoFrame::NumPlanes(frame->format());
105   size_t frame_size = 0;
106   for (size_t i = 0; i < plane_count; ++i) {
107     // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
108     DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)),
109               reinterpret_cast<void*>((frame->data(0) + frame_size)))
110         << "plane=" << i;
111     frame_size += frame->stride(i) * frame->rows(i);
112   }
113
114   Send(new AcceleratedVideoEncoderMsg_Encode(
115       route_id_, next_frame_id_, handle, frame_size, force_keyframe));
116   frame_map_[next_frame_id_] = frame;
117
118   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
119   next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF;
120 }
121
122 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
123     const media::BitstreamBuffer& buffer) {
124   if (!channel_)
125     return;
126   base::SharedMemoryHandle handle =
127       channel_->ShareToGpuProcess(buffer.handle());
128   if (!base::SharedMemory::IsHandleValid(handle)) {
129     DLOG(ERROR) << "UseOutputBitstreamBuffer(): failed to duplicate buffer "
130                    "handle for GPU process: buffer.id()=" << buffer.id();
131     NotifyError(kPlatformFailureError);
132     return;
133   }
134   Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
135       route_id_, buffer.id(), handle, buffer.size()));
136 }
137
138 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
139     uint32 bitrate,
140     uint32 framerate) {
141   Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
142       route_id_, bitrate, framerate));
143 }
144
145 void GpuVideoEncodeAcceleratorHost::Destroy() {
146   Send(new GpuChannelMsg_DestroyVideoEncoder(route_id_));
147   delete this;
148 }
149
150 void GpuVideoEncodeAcceleratorHost::NotifyError(Error error) {
151   DVLOG(2) << "NotifyError(): error=" << error;
152   base::MessageLoopProxy::current()->PostTask(
153       FROM_HERE,
154       base::Bind(&media::VideoEncodeAccelerator::Client::NotifyError,
155                  client_ptr_factory_.GetWeakPtr(),
156                  error));
157 }
158
159 void GpuVideoEncodeAcceleratorHost::OnNotifyInitializeDone() {
160   DVLOG(2) << "OnNotifyInitializeDone()";
161   if (client_)
162     client_->NotifyInitializeDone();
163 }
164
165 void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
166     uint32 input_count,
167     const gfx::Size& input_coded_size,
168     uint32 output_buffer_size) {
169   DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
170            << ", input_coded_size=" << input_coded_size.ToString()
171            << ", output_buffer_size=" << output_buffer_size;
172   if (client_) {
173     client_->RequireBitstreamBuffers(
174         input_count, input_coded_size, output_buffer_size);
175   }
176 }
177
178 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) {
179   DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id;
180   if (!frame_map_.erase(frame_id)) {
181     DLOG(ERROR) << "OnNotifyInputDone(): "
182                    "invalid frame_id=" << frame_id;
183     // See OnNotifyError for why this needs to be the last thing in this
184     // function.
185     OnNotifyError(kPlatformFailureError);
186     return;
187   }
188 }
189
190 void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
191     int32 bitstream_buffer_id,
192     uint32 payload_size,
193     bool key_frame) {
194   DVLOG(3) << "OnBitstreamBufferReady(): "
195               "bitstream_buffer_id=" << bitstream_buffer_id
196            << ", payload_size=" << payload_size
197            << ", key_frame=" << key_frame;
198   if (client_)
199     client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
200 }
201
202 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
203   DVLOG(2) << "OnNotifyError(): error=" << error;
204   if (!client_)
205     return;
206   client_ptr_factory_.InvalidateWeakPtrs();
207
208   // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
209   // last thing done on this stack!
210   media::VideoEncodeAccelerator::Client* client = NULL;
211   std::swap(client_, client);
212   client->NotifyError(error);
213 }
214
215 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
216   if (!channel_) {
217     DLOG(ERROR) << "Send(): no channel";
218     delete message;
219     NotifyError(kPlatformFailureError);
220   } else if (!channel_->Send(message)) {
221     DLOG(ERROR) << "Send(): sending failed: message->type()="
222                 << message->type();
223     NotifyError(kPlatformFailureError);
224   }
225 }
226
227 }  // namespace content