Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Side by Side Diff: content/renderer/pepper/pepper_media_stream_video_track_host.cc

Issue 150403006: [PPAPI][MediaStream] Support configure for video input. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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_media_stream_video_track_host.h" 5 #include "content/renderer/pepper/pepper_media_stream_video_track_host.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "media/base/yuv_convert.h"
8 #include "ppapi/c/pp_errors.h" 9 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/c/ppb_video_frame.h" 10 #include "ppapi/c/ppb_video_frame.h"
11 #include "ppapi/host/dispatch_host_message.h"
12 #include "ppapi/host/host_message_context.h"
13 #include "ppapi/proxy/ppapi_messages.h"
10 #include "ppapi/shared_impl/media_stream_buffer.h" 14 #include "ppapi/shared_impl/media_stream_buffer.h"
15 #include "third_party/libyuv/include/libyuv/scale.h"
11 16
12 using media::VideoFrame; 17 using media::VideoFrame;
18 using ppapi::host::HostMessageContext;
19 using ppapi::MediaStreamVideoTrackShared;
20 using ppapi::proxy::SerializedHandle;
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 order
Peng 2014/02/13 17:19:11 Sorry. Which one is not in order?
13 21
14 namespace { 22 namespace {
15 23
16 // TODO(penghuang): make it configurable. 24 const int32_t kNumberOfBuffers = 4;
17 const int32_t kNumberOfFrames = 4; 25 const int32_t kMaxNumberOfBuffers = 8;
18 26
19 PP_VideoFrame_Format ToPpapiFormat(VideoFrame::Format format) { 27 PP_VideoFrame_Format ToPpapiFormat(VideoFrame::Format format) {
20 switch (format) { 28 switch (format) {
21 case VideoFrame::YV12: 29 case VideoFrame::YV12:
22 return PP_VIDEOFRAME_FORMAT_YV12; 30 return PP_VIDEOFRAME_FORMAT_YV12;
23 case VideoFrame::YV16:
24 return PP_VIDEOFRAME_FORMAT_YV16;
25 case VideoFrame::I420: 31 case VideoFrame::I420:
26 return PP_VIDEOFRAME_FORMAT_I420; 32 return PP_VIDEOFRAME_FORMAT_I420;
27 case VideoFrame::YV12A:
28 return PP_VIDEOFRAME_FORMAT_YV12A;
29 case VideoFrame::YV12J:
30 return PP_VIDEOFRAME_FORMAT_YV12J;
31 default: 33 default:
32 DVLOG(1) << "Unsupported pixel format " << format; 34 DVLOG(1) << "Unsupported pixel format " << format;
33 return PP_VIDEOFRAME_FORMAT_UNKNOWN; 35 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
34 } 36 }
35 } 37 }
36 38
39 VideoFrame::Format FromPpapiFormat(PP_VideoFrame_Format format) {
40 switch (format) {
41 case PP_VIDEOFRAME_FORMAT_YV12:
42 return VideoFrame::YV12;
43 case PP_VIDEOFRAME_FORMAT_I420:
44 return VideoFrame::I420;
45 default:
46 DVLOG(1) << "Unsupported pixel format " << format;
47 return VideoFrame::UNKNOWN;
48 }
49 }
50
51 gfx::Size ComputeSize(const gfx::Size& frame,
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 ComputeSize and ComputeFormat are not so obvious.
Peng 2014/02/13 17:19:11 Done.
52 const gfx::Size& plugin) {
53 return gfx::Size(plugin.width() ? plugin.width() : frame.width(),
54 plugin.height() ? plugin.height() : frame.height());
55 }
56
57 PP_VideoFrame_Format ComputeFormat(PP_VideoFrame_Format frame,
58 PP_VideoFrame_Format plugin) {
59 return plugin != PP_VIDEOFRAME_FORMAT_UNKNOWN ? plugin : frame;
60 }
61
62 void ConvertFromMediaVideoFrame(const scoped_refptr<media::VideoFrame>& src,
63 uint8_t* dst,
64 PP_VideoFrame_Format dst_format,
65 const gfx::Size& dst_size) {
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 nit, prefer to have read only args and then read/w
Peng 2014/02/13 17:19:11 Done.
66 CHECK(src->format() == VideoFrame::YV12 ||
67 src->format() == VideoFrame::I420);
68 if (dst_format == PP_VIDEOFRAME_FORMAT_BGRA) {
69 if (src->coded_size() == dst_size) {
70 media::ConvertYUVToRGB32(src->data(VideoFrame::kYPlane),
71 src->data(VideoFrame::kUPlane),
72 src->data(VideoFrame::kVPlane),
73 dst,
74 dst_size.width(),
75 dst_size.height(),
76 src->stride(VideoFrame::kYPlane),
77 src->stride(VideoFrame::kUPlane),
78 dst_size.width() * 4,
79 media::YV12);
80 } else {
81 media::ScaleYUVToRGB32(src->data(VideoFrame::kYPlane),
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 I think call ScaleYUVToRGB32 with the same size is
Peng 2014/02/13 17:19:11 I am not sure. Probably they are not same. I check
82 src->data(VideoFrame::kUPlane),
83 src->data(VideoFrame::kVPlane),
84 dst,
85 src->coded_size().width(),
86 src->coded_size().height(),
87 dst_size.width(),
88 dst_size.height(),
89 src->stride(VideoFrame::kYPlane),
90 src->stride(VideoFrame::kUPlane),
91 dst_size.width() * 4,
92 media::YV12,
93 media::ROTATE_0,
94 media::FILTER_BILINEAR);
95 }
96 } else if (dst_format == PP_VIDEOFRAME_FORMAT_YV12 ||
97 dst_format == PP_VIDEOFRAME_FORMAT_I420) {
98 static const size_t kPlanes[][3] = {
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 kPlanesOrder?
Peng 2014/02/13 17:19:11 Done.
99 { VideoFrame::kYPlane, VideoFrame::kVPlane, VideoFrame::kUPlane }, // YV12
100 { VideoFrame::kYPlane, VideoFrame::kUPlane, VideoFrame::kVPlane }, // I420
101 };
102 const int plane_order = (dst_format == PP_VIDEOFRAME_FORMAT_YV12) ? 0 : 1;
103
104 if (src->coded_size() == dst_size) {
105 for (int i = 0; i < 3; i++) {
106 size_t plane = kPlanes[plane_order][i];
107 int32_t n = src->stride(plane) * src->rows(plane);
108 memcpy(dst, src->data(plane), n);
109 dst += n;
110 }
111 } else {
112 int w = dst_size.width();
113 int h = dst_size.height();
114 libyuv::ScalePlane(src->data(kPlanes[plane_order][0]),
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 dito, I think ScalePlane will just do copy if the
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 And I think you should be able to just use I420Sca
Peng 2014/02/13 17:19:11 Done.
Peng 2014/02/13 17:19:11 Because we support YV12 & I420 two formats. Use I4
115 src->stride(kPlanes[plane_order][0]),
116 src->coded_size().width(),
117 src->coded_size().height(),
118 dst, w, w, h, libyuv::kFilterBox);
119 dst += w * h;
120 w /= 2;
121 h /= 2;
122 libyuv::ScalePlane(src->data(kPlanes[plane_order][1]),
123 src->stride(kPlanes[plane_order][1]),
124 src->coded_size().width() / 2,
125 src->coded_size().height() / 2,
126 dst, w, w, h, libyuv::kFilterBox);
127 dst += w * h;
128 libyuv::ScalePlane(src->data(kPlanes[plane_order][2]),
129 src->stride(kPlanes[plane_order][2]),
130 src->coded_size().width() / 2,
131 src->coded_size().height() / 2,
132 dst, w, w, h, libyuv::kFilterBox);
133 }
134 } else {
135 NOTREACHED();
136 }
137 }
138
37 } // namespace 139 } // namespace
38 140
39 namespace content { 141 namespace content {
40 142
41 PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost( 143 PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost(
42 RendererPpapiHost* host, 144 RendererPpapiHost* host,
43 PP_Instance instance, 145 PP_Instance instance,
44 PP_Resource resource, 146 PP_Resource resource,
45 const blink::WebMediaStreamTrack& track) 147 const blink::WebMediaStreamTrack& track)
46 : PepperMediaStreamTrackHostBase(host, instance, resource), 148 : PepperMediaStreamTrackHostBase(host, instance, resource),
47 track_(track), 149 track_(track),
48 connected_(false), 150 connected_(false),
49 frame_format_(VideoFrame::UNKNOWN), 151 buffers_initialized_(false),
152 buffers_(kNumberOfBuffers),
153 frame_format_(PP_VIDEOFRAME_FORMAT_UNKNOWN),
154 plugin_frame_format_(PP_VIDEOFRAME_FORMAT_UNKNOWN),
50 frame_data_size_(0) { 155 frame_data_size_(0) {
51 DCHECK(!track_.isNull()); 156 DCHECK(!track_.isNull());
52 } 157 }
53 158
54 PepperMediaStreamVideoTrackHost::~PepperMediaStreamVideoTrackHost() { 159 PepperMediaStreamVideoTrackHost::~PepperMediaStreamVideoTrackHost() {
55 OnClose(); 160 OnClose();
56 } 161 }
57 162
163 void PepperMediaStreamVideoTrackHost::InitBuffers() {
164 gfx::Size size = ComputeSize(frame_size_, plugin_frame_size_);
165 DCHECK(!size.IsEmpty());
166
167 PP_VideoFrame_Format format =
168 ComputeFormat(frame_format_, plugin_frame_format_);
169 DCHECK_NE(format, PP_VIDEOFRAME_FORMAT_UNKNOWN);
170
171 if (format == PP_VIDEOFRAME_FORMAT_BGRA) {
172 frame_data_size_ = size.width() * size.height() * 4;
173 } else {
174 frame_data_size_ = VideoFrame::AllocationSize(FromPpapiFormat(format),
175 size);
176 }
177
178 DCHECK_GT(frame_data_size_, 0U);
179 int32_t buffer_size =
180 sizeof(ppapi::MediaStreamBuffer::Video) + frame_data_size_;
181 bool result = PepperMediaStreamTrackHostBase::InitBuffers(buffers_,
182 buffer_size);
183 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin.
184 CHECK(result);
185 }
186
58 void PepperMediaStreamVideoTrackHost::OnClose() { 187 void PepperMediaStreamVideoTrackHost::OnClose() {
59 if (connected_) { 188 if (connected_) {
60 MediaStreamVideoSink::RemoveFromVideoTrack(this, track_); 189 MediaStreamVideoSink::RemoveFromVideoTrack(this, track_);
61 connected_ = false; 190 connected_ = false;
62 } 191 }
63 } 192 }
64 193
65 void PepperMediaStreamVideoTrackHost::OnVideoFrame( 194 void PepperMediaStreamVideoTrackHost::OnVideoFrame(
66 const scoped_refptr<VideoFrame>& frame) { 195 const scoped_refptr<VideoFrame>& frame) {
67 DCHECK(frame); 196 DCHECK(frame);
68 // TODO(penghuang): Check |frame->end_of_stream()| and close the track. 197 // TODO(penghuang): Check |frame->end_of_stream()| and close the track.
69 PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format()); 198 PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format());
70 if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN) 199 if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN)
71 return; 200 return;
72 201
73 if (frame_size_ != frame->coded_size() || frame_format_ != frame->format()) { 202 if (!buffers_initialized_) {
74 frame_size_ = frame->coded_size(); 203 frame_size_ = frame->coded_size();
75 frame_format_ = frame->format(); 204 frame_format_ = ppformat;
76 // TODO(penghuang): Support changing |frame_size_| & |frame_format_| more 205 InitBuffers();
77 // than once. 206 buffers_initialized_ = true;
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 set buffers_initialized_ inside InitBuffers
Peng 2014/02/13 17:19:11 because we will called InitBuffers() multiple time
78 DCHECK(!frame_data_size_);
79 frame_data_size_ = VideoFrame::AllocationSize(frame_format_, frame_size_);
80 int32_t size = sizeof(ppapi::MediaStreamBuffer::Video) + frame_data_size_;
81 bool result = InitBuffers(kNumberOfFrames, size);
82 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin.
83 CHECK(result);
84 } 207 }
85 208
86 int32_t index = buffer_manager()->DequeueBuffer(); 209 int32_t index = buffer_manager()->DequeueBuffer();
87 // Drop frames if the underlying buffer is full. 210 // Drop frames if the underlying buffer is full.
88 if (index < 0) 211 if (index < 0) {
212 DVLOG(1) << "A frame is dropped.";
89 return; 213 return;
214 }
90 215
91 // TODO(penghuang): support format conversion and size scaling. 216 DCHECK(frame->coded_size() == frame_size_);
217 DCHECK_EQ(ppformat, frame_format_);
218
219 gfx::Size size = ComputeSize(frame_size_, plugin_frame_size_);
220 PP_VideoFrame_Format format = ComputeFormat(frame_format_,
221 plugin_frame_format_);
92 ppapi::MediaStreamBuffer::Video* buffer = 222 ppapi::MediaStreamBuffer::Video* buffer =
93 &(buffer_manager()->GetBufferPointer(index)->video); 223 &(buffer_manager()->GetBufferPointer(index)->video);
94 buffer->header.size = buffer_manager()->buffer_size(); 224 buffer->header.size = buffer_manager()->buffer_size();
95 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO; 225 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
96 buffer->timestamp = frame->GetTimestamp().InSecondsF(); 226 buffer->timestamp = frame->GetTimestamp().InSecondsF();
97 buffer->format = ppformat; 227 buffer->format = format;
98 buffer->size.width = frame->coded_size().width(); 228 buffer->size.width = size.width();
99 buffer->size.height = frame->coded_size().height(); 229 buffer->size.height = size.height();
100 buffer->data_size = frame_data_size_; 230 buffer->data_size = frame_data_size_;
101
102 COMPILE_ASSERT(VideoFrame::kYPlane == 0, y_plane_should_be_0);
103 COMPILE_ASSERT(VideoFrame::kUPlane == 1, u_plane_should_be_1);
104 COMPILE_ASSERT(VideoFrame::kVPlane == 2, v_plane_should_be_2);
105
106 uint8_t* dst = buffer->data; 231 uint8_t* dst = buffer->data;
107 size_t num_planes = VideoFrame::NumPlanes(frame->format()); 232 ConvertFromMediaVideoFrame(frame, dst, format, size);
108 for (size_t i = 0; i < num_planes; ++i) {
109 const uint8_t* src = frame->data(i);
110 const size_t row_bytes = frame->row_bytes(i);
111 const size_t src_stride = frame->stride(i);
112 int rows = frame->rows(i);
113 for (int j = 0; j < rows; ++j) {
114 memcpy(dst, src, row_bytes);
115 dst += row_bytes;
116 src += src_stride;
117 }
118 }
119
120 SendEnqueueBufferMessageToPlugin(index); 233 SendEnqueueBufferMessageToPlugin(index);
121 } 234 }
122 235
123 void PepperMediaStreamVideoTrackHost::DidConnectPendingHostToResource() { 236 void PepperMediaStreamVideoTrackHost::DidConnectPendingHostToResource() {
124 if (!connected_) { 237 if (!connected_) {
125 MediaStreamVideoSink::AddToVideoTrack(this, track_); 238 MediaStreamVideoSink::AddToVideoTrack(this, track_);
126 connected_ = true; 239 connected_ = true;
127 } 240 }
128 } 241 }
129 242
243 int32_t PepperMediaStreamVideoTrackHost::OnResourceMessageReceived(
244 const IPC::Message& msg,
245 HostMessageContext* context) {
246 IPC_BEGIN_MESSAGE_MAP(PepperMediaStreamVideoTrackHost, msg)
247 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
248 PpapiHostMsg_MediaStreamVideoTrack_Configure,
249 OnHostMsgConfigure)
250 IPC_END_MESSAGE_MAP()
251 return PepperMediaStreamTrackHostBase::OnResourceMessageReceived(msg,
252 context);
253 }
254
255 int32_t PepperMediaStreamVideoTrackHost::OnHostMsgConfigure(
256 HostMessageContext* context,
257 const MediaStreamVideoTrackShared::Attributes& attributes) {
258 CHECK(MediaStreamVideoTrackShared::VerifyAttributes(attributes));
259
260 bool changed = false;
261 const uint32_t kWHMask = MediaStreamVideoTrackShared::Attributes::MASK_WIDTH |
262 MediaStreamVideoTrackShared::Attributes::MASK_HEIGHT;
263 if (attributes.mask & kWHMask) {
264 gfx::Size new_size = plugin_frame_size_;
265 if (attributes.mask & MediaStreamVideoTrackShared::Attributes::MASK_WIDTH)
266 new_size.set_width(attributes.width);
267 if (attributes.mask & MediaStreamVideoTrackShared::Attributes::MASK_HEIGHT)
268 new_size.set_height(attributes.height);
269 if (ComputeSize(frame_size_, plugin_frame_size_) !=
270 ComputeSize(frame_size_, new_size)) {
271 changed = true;
272 }
273 plugin_frame_size_ = new_size;
274 }
275
276 if (attributes.mask & MediaStreamVideoTrackShared::Attributes::MASK_BUFFERS) {
277 int32_t buffers = attributes.buffers ?
278 std::min(kMaxNumberOfBuffers, attributes.buffers) : kNumberOfBuffers;
279 if (buffers != buffers_) {
280 buffers_ = buffers;
281 changed = true;
282 }
283 }
284
285 if (attributes.mask & MediaStreamVideoTrackShared::Attributes::MASK_FORMAT) {
286 if (plugin_frame_format_ != attributes.format) {
287 PP_VideoFrame_Format original_format = ComputeFormat(
288 frame_format_, plugin_frame_format_);
289 PP_VideoFrame_Format new_format = ComputeFormat(
290 frame_format_, attributes.format);
291 if (new_format != original_format)
292 changed = true;
293 plugin_frame_format_ = attributes.format;
294 }
295 LOG(ERROR) << "format =" << plugin_frame_format_;
296 }
297
298 // If buffers has been initialized, we need re-initialize it with
299 // new settings. Otherwise, we will initialize buffer when we receive
Ronghua Wu (Left Chromium) 2014/02/12 19:54:15 why do we need to "initialize buffer when receive
Peng 2014/02/13 17:19:11 Because plugin may only provide part for attribute
300 // the first frame.
301 if (changed && buffers_initialized_)
302 InitBuffers();
303
304 context->reply_msg = PpapiPluginMsg_MediaStreamVideoTrack_ConfigureReply();
305 return PP_OK;
306 }
307
130 } // namespace content 308 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698