Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_video_source_host.cc
1 // Copyright (c) 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/renderer/pepper/pepper_video_source_host.h"
6
7 #include "base/bind.h"
8 #include "base/numerics/safe_conversions.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "content/renderer/pepper/ppb_image_data_impl.h"
11 #include "content/renderer/render_thread_impl.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/host/dispatch_host_message.h"
14 #include "ppapi/host/ppapi_host.h"
15 #include "ppapi/proxy/host_dispatcher.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/proxy/ppb_image_data_proxy.h"
18 #include "ppapi/shared_impl/scoped_pp_resource.h"
19 #include "ppapi/thunk/enter.h"
20 #include "ppapi/thunk/ppb_image_data_api.h"
21 #include "third_party/libyuv/include/libyuv/convert.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23
24 using ppapi::host::HostMessageContext;
25 using ppapi::host::ReplyMessageContext;
26
27 namespace content {
28
29 PepperVideoSourceHost::FrameReceiver::FrameReceiver(
30     const base::WeakPtr<PepperVideoSourceHost>& host)
31     : host_(host) {}
32
33 PepperVideoSourceHost::FrameReceiver::~FrameReceiver() {}
34
35 void PepperVideoSourceHost::FrameReceiver::GotFrame(
36     const scoped_refptr<media::VideoFrame>& frame) {
37   DCHECK(thread_checker_.CalledOnValidThread());
38   if (host_.get()) {
39     // Hold a reference to the new frame and release the previous.
40     host_->last_frame_ = frame;
41
42     if (host_->get_frame_pending_)
43       host_->SendGetFrameReply();
44   }
45 }
46
47 PepperVideoSourceHost::PepperVideoSourceHost(RendererPpapiHost* host,
48                                              PP_Instance instance,
49                                              PP_Resource resource)
50     : ResourceHost(host->GetPpapiHost(), instance, resource),
51       renderer_ppapi_host_(host),
52       source_handler_(new VideoSourceHandler(NULL)),
53       get_frame_pending_(false),
54       weak_factory_(this) {
55   frame_receiver_ = new FrameReceiver(weak_factory_.GetWeakPtr());
56   memset(&shared_image_desc_, 0, sizeof(shared_image_desc_));
57 }
58
59 PepperVideoSourceHost::~PepperVideoSourceHost() { Close(); }
60
61 int32_t PepperVideoSourceHost::OnResourceMessageReceived(
62     const IPC::Message& msg,
63     HostMessageContext* context) {
64   PPAPI_BEGIN_MESSAGE_MAP(PepperVideoSourceHost, msg)
65     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoSource_Open,
66                                       OnHostMsgOpen)
67     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoSource_GetFrame,
68                                         OnHostMsgGetFrame)
69     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoSource_Close,
70                                         OnHostMsgClose)
71   PPAPI_END_MESSAGE_MAP()
72   return PP_ERROR_FAILED;
73 }
74
75 int32_t PepperVideoSourceHost::OnHostMsgOpen(HostMessageContext* context,
76                                              const std::string& stream_url) {
77   GURL gurl(stream_url);
78   if (!gurl.is_valid())
79     return PP_ERROR_BADARGUMENT;
80
81   if (!source_handler_->Open(gurl.spec(), frame_receiver_.get()))
82     return PP_ERROR_BADARGUMENT;
83
84   stream_url_ = gurl.spec();
85
86   ReplyMessageContext reply_context = context->MakeReplyMessageContext();
87   reply_context.params.set_result(PP_OK);
88   host()->SendReply(reply_context, PpapiPluginMsg_VideoSource_OpenReply());
89   return PP_OK_COMPLETIONPENDING;
90 }
91
92 int32_t PepperVideoSourceHost::OnHostMsgGetFrame(HostMessageContext* context) {
93   if (!source_handler_.get())
94     return PP_ERROR_FAILED;
95   if (get_frame_pending_)
96     return PP_ERROR_INPROGRESS;
97
98   reply_context_ = context->MakeReplyMessageContext();
99   get_frame_pending_ = true;
100
101   // If a frame is ready, try to convert it and send the reply.
102   if (last_frame_.get())
103     SendGetFrameReply();
104
105   return PP_OK_COMPLETIONPENDING;
106 }
107
108 int32_t PepperVideoSourceHost::OnHostMsgClose(HostMessageContext* context) {
109   Close();
110   return PP_OK;
111 }
112
113 void PepperVideoSourceHost::SendGetFrameReply() {
114   DCHECK(get_frame_pending_);
115   get_frame_pending_ = false;
116
117   DCHECK(last_frame_.get());
118   scoped_refptr<media::VideoFrame> frame(last_frame_);
119   last_frame_ = NULL;
120
121   const int dst_width = frame->visible_rect().width();
122   const int dst_height = frame->visible_rect().height();
123
124   // Note: We try to reuse the shared memory for the previous frame here. This
125   // means that the previous frame may be overwritten and is no longer valid
126   // after calling this function again.
127   IPC::PlatformFileForTransit image_handle;
128   uint32_t byte_count;
129   if (shared_image_.get() && dst_width == shared_image_->width() &&
130       dst_height == shared_image_->height()) {
131     // We have already allocated the correct size in shared memory. We need to
132     // duplicate the handle for IPC however, which will close down the
133     // duplicated handle when it's done.
134     int local_fd = 0;
135     if (shared_image_->GetSharedMemory(&local_fd, &byte_count) != PP_OK) {
136       SendGetFrameErrorReply(PP_ERROR_FAILED);
137       return;
138     }
139
140     ppapi::proxy::HostDispatcher* dispatcher =
141         ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
142     if (!dispatcher) {
143       SendGetFrameErrorReply(PP_ERROR_FAILED);
144       return;
145     }
146
147 #if defined(OS_WIN)
148     image_handle = dispatcher->ShareHandleWithRemote(
149         reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)), false);
150 #elif defined(OS_POSIX)
151     image_handle = dispatcher->ShareHandleWithRemote(local_fd, false);
152 #else
153 #error Not implemented.
154 #endif
155   } else {
156     // We need to allocate new shared memory.
157     shared_image_ = NULL;  // Release any previous image.
158
159     ppapi::ScopedPPResource resource(
160         ppapi::ScopedPPResource::PassRef(),
161         ppapi::proxy::PPB_ImageData_Proxy::CreateImageData(
162             pp_instance(),
163             ppapi::PPB_ImageData_Shared::SIMPLE,
164             PP_IMAGEDATAFORMAT_BGRA_PREMUL,
165             PP_MakeSize(dst_width, dst_height),
166             false /* init_to_zero */,
167             &shared_image_desc_,
168             &image_handle,
169             &byte_count));
170     if (!resource) {
171       SendGetFrameErrorReply(PP_ERROR_FAILED);
172       return;
173     }
174
175     ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API>
176         enter_resource(resource, false);
177     if (enter_resource.failed()) {
178       SendGetFrameErrorReply(PP_ERROR_FAILED);
179       return;
180     }
181
182     shared_image_ = static_cast<PPB_ImageData_Impl*>(enter_resource.object());
183     if (!shared_image_.get()) {
184       SendGetFrameErrorReply(PP_ERROR_FAILED);
185       return;
186     }
187
188     DCHECK(!shared_image_->IsMapped());  // New memory should not be mapped.
189     if (!shared_image_->Map() || !shared_image_->GetMappedBitmap() ||
190         !shared_image_->GetMappedBitmap()->getPixels()) {
191       shared_image_ = NULL;
192       SendGetFrameErrorReply(PP_ERROR_FAILED);
193       return;
194     }
195   }
196
197   const SkBitmap* bitmap = shared_image_->GetMappedBitmap();
198   if (!bitmap) {
199     SendGetFrameErrorReply(PP_ERROR_FAILED);
200     return;
201   }
202
203   uint8_t* bitmap_pixels = static_cast<uint8_t*>(bitmap->getPixels());
204   if (!bitmap_pixels) {
205     SendGetFrameErrorReply(PP_ERROR_FAILED);
206     return;
207   }
208
209   // Calculate that portion of the |frame| that should be copied into
210   // |bitmap|. If |frame| has been cropped,
211   // frame->coded_size() != frame->visible_rect().
212   const int src_width = frame->coded_size().width();
213   const int src_height = frame->coded_size().height();
214   DCHECK(src_width >= dst_width && src_height >= dst_height);
215
216   const int horiz_crop = frame->visible_rect().x();
217   const int vert_crop = frame->visible_rect().y();
218
219   const uint8* src_y = frame->data(media::VideoFrame::kYPlane) +
220                        (src_width * vert_crop + horiz_crop);
221   const int center = (src_width + 1) / 2;
222   const uint8* src_u = frame->data(media::VideoFrame::kUPlane) +
223                        (center * vert_crop + horiz_crop) / 2;
224   const uint8* src_v = frame->data(media::VideoFrame::kVPlane) +
225                        (center * vert_crop + horiz_crop) / 2;
226
227   libyuv::I420ToARGB(src_y,
228                      frame->stride(media::VideoFrame::kYPlane),
229                      src_u,
230                      frame->stride(media::VideoFrame::kUPlane),
231                      src_v,
232                      frame->stride(media::VideoFrame::kVPlane),
233                      bitmap_pixels,
234                      bitmap->rowBytes(),
235                      dst_width,
236                      dst_height);
237
238   ppapi::HostResource host_resource;
239   host_resource.SetHostResource(pp_instance(), shared_image_->GetReference());
240
241   // Convert a video timestamp to a PP_TimeTicks (a double, in seconds).
242   const PP_TimeTicks timestamp = frame->timestamp().InSecondsF();
243
244   ppapi::proxy::SerializedHandle serialized_handle;
245   serialized_handle.set_shmem(image_handle, byte_count);
246   reply_context_.params.AppendHandle(serialized_handle);
247
248   host()->SendReply(reply_context_,
249                     PpapiPluginMsg_VideoSource_GetFrameReply(
250                         host_resource, shared_image_desc_, timestamp));
251
252   reply_context_ = ppapi::host::ReplyMessageContext();
253 }
254
255 void PepperVideoSourceHost::SendGetFrameErrorReply(int32_t error) {
256   reply_context_.params.set_result(error);
257   host()->SendReply(
258       reply_context_,
259       PpapiPluginMsg_VideoSource_GetFrameReply(
260           ppapi::HostResource(), PP_ImageDataDesc(), 0.0 /* timestamp */));
261   reply_context_ = ppapi::host::ReplyMessageContext();
262 }
263
264 void PepperVideoSourceHost::Close() {
265   if (source_handler_.get() && !stream_url_.empty())
266     source_handler_->Close(frame_receiver_.get());
267
268   source_handler_.reset(NULL);
269   stream_url_.clear();
270
271   shared_image_ = NULL;
272 }
273
274 }  // namespace content