OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/pepper/pepper_video_source_host.h" | 5 #include "content/renderer/pepper/pepper_video_source_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/numerics/safe_conversions.h" | 8 #include "base/numerics/safe_conversions.h" |
9 #include "content/public/renderer/renderer_ppapi_host.h" | 9 #include "content/public/renderer/renderer_ppapi_host.h" |
10 #include "content/renderer/pepper/ppb_image_data_impl.h" | 10 #include "content/renderer/pepper/ppb_image_data_impl.h" |
11 #include "content/renderer/render_thread_impl.h" | 11 #include "content/renderer/render_thread_impl.h" |
12 #include "ppapi/c/pp_errors.h" | 12 #include "ppapi/c/pp_errors.h" |
13 #include "ppapi/host/dispatch_host_message.h" | 13 #include "ppapi/host/dispatch_host_message.h" |
14 #include "ppapi/host/ppapi_host.h" | 14 #include "ppapi/host/ppapi_host.h" |
15 #include "ppapi/proxy/host_dispatcher.h" | 15 #include "ppapi/proxy/host_dispatcher.h" |
16 #include "ppapi/proxy/ppapi_messages.h" | 16 #include "ppapi/proxy/ppapi_messages.h" |
17 #include "ppapi/proxy/ppb_image_data_proxy.h" | 17 #include "ppapi/proxy/ppb_image_data_proxy.h" |
18 #include "ppapi/shared_impl/scoped_pp_resource.h" | 18 #include "ppapi/shared_impl/scoped_pp_resource.h" |
19 #include "ppapi/thunk/enter.h" | 19 #include "ppapi/thunk/enter.h" |
20 #include "ppapi/thunk/ppb_image_data_api.h" | 20 #include "ppapi/thunk/ppb_image_data_api.h" |
21 #include "third_party/libyuv/include/libyuv/convert.h" | 21 #include "third_party/libyuv/include/libyuv/convert.h" |
| 22 #include "third_party/libyuv/include/libyuv/scale.h" |
22 #include "third_party/skia/include/core/SkBitmap.h" | 23 #include "third_party/skia/include/core/SkBitmap.h" |
23 | 24 |
24 using ppapi::host::HostMessageContext; | 25 using ppapi::host::HostMessageContext; |
25 using ppapi::host::ReplyMessageContext; | 26 using ppapi::host::ReplyMessageContext; |
26 | 27 |
27 namespace content { | 28 namespace content { |
28 | 29 |
29 PepperVideoSourceHost::FrameReceiver::FrameReceiver( | 30 PepperVideoSourceHost::FrameReceiver::FrameReceiver( |
30 const base::WeakPtr<PepperVideoSourceHost>& host) | 31 const base::WeakPtr<PepperVideoSourceHost>& host) |
31 : host_(host) {} | 32 : host_(host) {} |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 int32_t PepperVideoSourceHost::OnHostMsgClose(HostMessageContext* context) { | 109 int32_t PepperVideoSourceHost::OnHostMsgClose(HostMessageContext* context) { |
109 Close(); | 110 Close(); |
110 return PP_OK; | 111 return PP_OK; |
111 } | 112 } |
112 | 113 |
113 void PepperVideoSourceHost::SendGetFrameReply() { | 114 void PepperVideoSourceHost::SendGetFrameReply() { |
114 DCHECK(get_frame_pending_); | 115 DCHECK(get_frame_pending_); |
115 get_frame_pending_ = false; | 116 get_frame_pending_ = false; |
116 | 117 |
117 DCHECK(last_frame_.get()); | 118 DCHECK(last_frame_.get()); |
118 scoped_refptr<media::VideoFrame> frame(last_frame_); | 119 const gfx::Size dst_size = last_frame_->natural_size(); |
119 last_frame_ = NULL; | |
120 | |
121 const int dst_width = frame->visible_rect().width(); | |
122 const int dst_height = frame->visible_rect().height(); | |
123 | 120 |
124 // Note: We try to reuse the shared memory for the previous frame here. This | 121 // 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 | 122 // means that the previous frame may be overwritten and is no longer valid |
126 // after calling this function again. | 123 // after calling this function again. |
127 IPC::PlatformFileForTransit image_handle; | 124 IPC::PlatformFileForTransit image_handle; |
128 uint32_t byte_count; | 125 uint32_t byte_count; |
129 if (shared_image_.get() && dst_width == shared_image_->width() && | 126 if (shared_image_.get() && dst_size.width() == shared_image_->width() && |
130 dst_height == shared_image_->height()) { | 127 dst_size.height() == shared_image_->height()) { |
131 // We have already allocated the correct size in shared memory. We need to | 128 // 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 | 129 // duplicate the handle for IPC however, which will close down the |
133 // duplicated handle when it's done. | 130 // duplicated handle when it's done. |
134 int local_fd = 0; | 131 int local_fd = 0; |
135 if (shared_image_->GetSharedMemory(&local_fd, &byte_count) != PP_OK) { | 132 if (shared_image_->GetSharedMemory(&local_fd, &byte_count) != PP_OK) { |
136 SendGetFrameErrorReply(PP_ERROR_FAILED); | 133 SendGetFrameErrorReply(PP_ERROR_FAILED); |
137 return; | 134 return; |
138 } | 135 } |
139 | 136 |
140 ppapi::proxy::HostDispatcher* dispatcher = | 137 ppapi::proxy::HostDispatcher* dispatcher = |
(...skipping 14 matching lines...) Expand all Loading... |
155 } else { | 152 } else { |
156 // We need to allocate new shared memory. | 153 // We need to allocate new shared memory. |
157 shared_image_ = NULL; // Release any previous image. | 154 shared_image_ = NULL; // Release any previous image. |
158 | 155 |
159 ppapi::ScopedPPResource resource( | 156 ppapi::ScopedPPResource resource( |
160 ppapi::ScopedPPResource::PassRef(), | 157 ppapi::ScopedPPResource::PassRef(), |
161 ppapi::proxy::PPB_ImageData_Proxy::CreateImageData( | 158 ppapi::proxy::PPB_ImageData_Proxy::CreateImageData( |
162 pp_instance(), | 159 pp_instance(), |
163 ppapi::PPB_ImageData_Shared::SIMPLE, | 160 ppapi::PPB_ImageData_Shared::SIMPLE, |
164 PP_IMAGEDATAFORMAT_BGRA_PREMUL, | 161 PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
165 PP_MakeSize(dst_width, dst_height), | 162 PP_MakeSize(dst_size.width(), dst_size.height()), |
166 false /* init_to_zero */, | 163 false /* init_to_zero */, |
167 &shared_image_desc_, | 164 &shared_image_desc_, |
168 &image_handle, | 165 &image_handle, |
169 &byte_count)); | 166 &byte_count)); |
170 if (!resource) { | 167 if (!resource) { |
171 SendGetFrameErrorReply(PP_ERROR_FAILED); | 168 SendGetFrameErrorReply(PP_ERROR_FAILED); |
172 return; | 169 return; |
173 } | 170 } |
174 | 171 |
175 ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API> | 172 ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API> |
(...skipping 23 matching lines...) Expand all Loading... |
199 SendGetFrameErrorReply(PP_ERROR_FAILED); | 196 SendGetFrameErrorReply(PP_ERROR_FAILED); |
200 return; | 197 return; |
201 } | 198 } |
202 | 199 |
203 uint8_t* bitmap_pixels = static_cast<uint8_t*>(bitmap->getPixels()); | 200 uint8_t* bitmap_pixels = static_cast<uint8_t*>(bitmap->getPixels()); |
204 if (!bitmap_pixels) { | 201 if (!bitmap_pixels) { |
205 SendGetFrameErrorReply(PP_ERROR_FAILED); | 202 SendGetFrameErrorReply(PP_ERROR_FAILED); |
206 return; | 203 return; |
207 } | 204 } |
208 | 205 |
209 // Calculate that portion of the |frame| that should be copied into | 206 // Calculate the portion of the |last_frame_| that should be copied into |
210 // |bitmap|. If |frame| has been cropped, | 207 // |bitmap|. If |last_frame_| is lazily scaled, then |
211 // frame->coded_size() != frame->visible_rect(). | 208 // last_frame_->visible_rect()._size() != last_frame_.natural_size(). |
212 const int src_width = frame->coded_size().width(); | 209 scoped_refptr<media::VideoFrame> frame; |
213 const int src_height = frame->coded_size().height(); | 210 if (dst_size == last_frame_->visible_rect().size()) { |
214 DCHECK(src_width >= dst_width && src_height >= dst_height); | 211 // No scaling is needed, convert directly from last_frame_. |
215 | 212 frame = last_frame_; |
216 const int horiz_crop = frame->visible_rect().x(); | 213 // Frame resolution doesn't change frequently, so don't keep any unnecessary |
217 const int vert_crop = frame->visible_rect().y(); | 214 // buffers around. |
218 | 215 scaled_frame_ = NULL; |
219 const uint8* src_y = frame->data(media::VideoFrame::kYPlane) + | 216 } else { |
220 (src_width * vert_crop + horiz_crop); | 217 // We need to create an intermediate scaled frame. Make sure we have |
221 const int center = (src_width + 1) / 2; | 218 // allocated one of correct size. |
222 const uint8* src_u = frame->data(media::VideoFrame::kUPlane) + | 219 if (!scaled_frame_.get() || scaled_frame_->coded_size() != dst_size) { |
223 (center * vert_crop + horiz_crop) / 2; | 220 scaled_frame_ = media::VideoFrame::CreateFrame( |
224 const uint8* src_v = frame->data(media::VideoFrame::kVPlane) + | 221 media::VideoFrame::I420, dst_size, gfx::Rect(dst_size), dst_size, |
225 (center * vert_crop + horiz_crop) / 2; | 222 last_frame_->timestamp()); |
| 223 if (!scaled_frame_.get()) { |
| 224 LOG(ERROR) << "Failed to allocate a media::VideoFrame"; |
| 225 SendGetFrameErrorReply(PP_ERROR_FAILED); |
| 226 return; |
| 227 } |
| 228 } |
| 229 libyuv::I420Scale(last_frame_->visible_data(media::VideoFrame::kYPlane), |
| 230 last_frame_->stride(media::VideoFrame::kYPlane), |
| 231 last_frame_->visible_data(media::VideoFrame::kUPlane), |
| 232 last_frame_->stride(media::VideoFrame::kUPlane), |
| 233 last_frame_->visible_data(media::VideoFrame::kVPlane), |
| 234 last_frame_->stride(media::VideoFrame::kVPlane), |
| 235 last_frame_->visible_rect().width(), |
| 236 last_frame_->visible_rect().height(), |
| 237 scaled_frame_->data(media::VideoFrame::kYPlane), |
| 238 scaled_frame_->stride(media::VideoFrame::kYPlane), |
| 239 scaled_frame_->data(media::VideoFrame::kUPlane), |
| 240 scaled_frame_->stride(media::VideoFrame::kUPlane), |
| 241 scaled_frame_->data(media::VideoFrame::kVPlane), |
| 242 scaled_frame_->stride(media::VideoFrame::kVPlane), |
| 243 dst_size.width(), |
| 244 dst_size.height(), |
| 245 libyuv::kFilterBilinear); |
| 246 frame = scaled_frame_; |
| 247 } |
| 248 last_frame_ = NULL; |
226 | 249 |
227 // TODO(magjed): Chrome OS is not ready for switching from BGRA to ARGB. | 250 // TODO(magjed): Chrome OS is not ready for switching from BGRA to ARGB. |
228 // Remove this once http://crbug/434007 is fixed. We have a corresponding | 251 // Remove this once http://crbug/434007 is fixed. We have a corresponding |
229 // problem when we receive frames from the effects plugin in PpFrameWriter. | 252 // problem when we receive frames from the effects plugin in PpFrameWriter. |
230 #if defined(OS_CHROMEOS) | 253 #if defined(OS_CHROMEOS) |
231 auto libyuv_i420_to_xxxx = &libyuv::I420ToBGRA; | 254 auto libyuv_i420_to_xxxx = &libyuv::I420ToBGRA; |
232 #else | 255 #else |
233 auto libyuv_i420_to_xxxx = &libyuv::I420ToARGB; | 256 auto libyuv_i420_to_xxxx = &libyuv::I420ToARGB; |
234 #endif | 257 #endif |
235 libyuv_i420_to_xxxx(src_y, | 258 libyuv_i420_to_xxxx(frame->visible_data(media::VideoFrame::kYPlane), |
236 frame->stride(media::VideoFrame::kYPlane), | 259 frame->stride(media::VideoFrame::kYPlane), |
237 src_u, | 260 frame->visible_data(media::VideoFrame::kUPlane), |
238 frame->stride(media::VideoFrame::kUPlane), | 261 frame->stride(media::VideoFrame::kUPlane), |
239 src_v, | 262 frame->visible_data(media::VideoFrame::kVPlane), |
240 frame->stride(media::VideoFrame::kVPlane), | 263 frame->stride(media::VideoFrame::kVPlane), |
241 bitmap_pixels, | 264 bitmap_pixels, |
242 bitmap->rowBytes(), | 265 bitmap->rowBytes(), |
243 dst_width, | 266 dst_size.width(), |
244 dst_height); | 267 dst_size.height()); |
245 | 268 |
246 ppapi::HostResource host_resource; | 269 ppapi::HostResource host_resource; |
247 host_resource.SetHostResource(pp_instance(), shared_image_->GetReference()); | 270 host_resource.SetHostResource(pp_instance(), shared_image_->GetReference()); |
248 | 271 |
249 // Convert a video timestamp to a PP_TimeTicks (a double, in seconds). | 272 // Convert a video timestamp to a PP_TimeTicks (a double, in seconds). |
250 const PP_TimeTicks timestamp = frame->timestamp().InSecondsF(); | 273 const PP_TimeTicks timestamp = frame->timestamp().InSecondsF(); |
251 | 274 |
252 ppapi::proxy::SerializedHandle serialized_handle; | 275 ppapi::proxy::SerializedHandle serialized_handle; |
253 serialized_handle.set_shmem(image_handle, byte_count); | 276 serialized_handle.set_shmem(image_handle, byte_count); |
254 reply_context_.params.AppendHandle(serialized_handle); | 277 reply_context_.params.AppendHandle(serialized_handle); |
(...skipping 18 matching lines...) Expand all Loading... |
273 if (source_handler_.get() && !stream_url_.empty()) | 296 if (source_handler_.get() && !stream_url_.empty()) |
274 source_handler_->Close(frame_receiver_.get()); | 297 source_handler_->Close(frame_receiver_.get()); |
275 | 298 |
276 source_handler_.reset(NULL); | 299 source_handler_.reset(NULL); |
277 stream_url_.clear(); | 300 stream_url_.clear(); |
278 | 301 |
279 shared_image_ = NULL; | 302 shared_image_ = NULL; |
280 } | 303 } |
281 | 304 |
282 } // namespace content | 305 } // namespace content |
OLD | NEW |