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

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: Fix review issues 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;
13 20
14 namespace { 21 namespace {
15 22
16 // TODO(penghuang): make it configurable. 23 const int32_t kDefaultNumberOfBuffers = 4;
17 const int32_t kNumberOfFrames = 4; 24 const int32_t kMaxNumberOfBuffers = 8;
25 // Filer mode for scaling frames.
26 const libyuv::FilterMode kFilterMode = libyuv::kFilterBox;
18 27
19 PP_VideoFrame_Format ToPpapiFormat(VideoFrame::Format format) { 28 PP_VideoFrame_Format ToPpapiFormat(VideoFrame::Format format) {
20 switch (format) { 29 switch (format) {
21 case VideoFrame::YV12: 30 case VideoFrame::YV12:
22 return PP_VIDEOFRAME_FORMAT_YV12; 31 return PP_VIDEOFRAME_FORMAT_YV12;
23 case VideoFrame::YV16:
24 return PP_VIDEOFRAME_FORMAT_YV16;
25 case VideoFrame::I420: 32 case VideoFrame::I420:
26 return PP_VIDEOFRAME_FORMAT_I420; 33 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: 34 default:
32 DVLOG(1) << "Unsupported pixel format " << format; 35 DVLOG(1) << "Unsupported pixel format " << format;
33 return PP_VIDEOFRAME_FORMAT_UNKNOWN; 36 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
34 } 37 }
35 } 38 }
36 39
40 VideoFrame::Format FromPpapiFormat(PP_VideoFrame_Format format) {
41 switch (format) {
42 case PP_VIDEOFRAME_FORMAT_YV12:
43 return VideoFrame::YV12;
44 case PP_VIDEOFRAME_FORMAT_I420:
45 return VideoFrame::I420;
46 default:
47 DVLOG(1) << "Unsupported pixel format " << format;
48 return VideoFrame::UNKNOWN;
49 }
50 }
51
52 // Compute size base on the size of frame received from MediaStreamVideoSink
53 // and size specified by plugin.
54 gfx::Size GetTargetSize(const gfx::Size& source,
55 const gfx::Size& plugin) {
56 return gfx::Size(plugin.width() ? plugin.width() : source.width(),
57 plugin.height() ? plugin.height() : source.height());
58 }
59
60 // Compute format base on the format of frame received from MediaStreamVideoSink
61 // and format specified by plugin.
62 PP_VideoFrame_Format GetTargetFormat(PP_VideoFrame_Format source,
63 PP_VideoFrame_Format plugin) {
64 return plugin != PP_VIDEOFRAME_FORMAT_UNKNOWN ? plugin : source;
65 }
66
67 void ConvertFromMediaVideoFrame(const scoped_refptr<media::VideoFrame>& src,
68 PP_VideoFrame_Format dst_format,
69 const gfx::Size& dst_size,
70 uint8_t* dst) {
71 CHECK(src->format() == VideoFrame::YV12 ||
72 src->format() == VideoFrame::I420);
73 if (dst_format == PP_VIDEOFRAME_FORMAT_BGRA) {
74 if (src->coded_size() == dst_size) {
75 media::ConvertYUVToRGB32(src->data(VideoFrame::kYPlane),
76 src->data(VideoFrame::kUPlane),
77 src->data(VideoFrame::kVPlane),
78 dst,
79 dst_size.width(),
80 dst_size.height(),
81 src->stride(VideoFrame::kYPlane),
82 src->stride(VideoFrame::kUPlane),
83 dst_size.width() * 4,
84 media::YV12);
85 } else {
86 media::ScaleYUVToRGB32(src->data(VideoFrame::kYPlane),
87 src->data(VideoFrame::kUPlane),
88 src->data(VideoFrame::kVPlane),
89 dst,
90 src->coded_size().width(),
91 src->coded_size().height(),
92 dst_size.width(),
93 dst_size.height(),
94 src->stride(VideoFrame::kYPlane),
95 src->stride(VideoFrame::kUPlane),
96 dst_size.width() * 4,
97 media::YV12,
98 media::ROTATE_0,
99 media::FILTER_BILINEAR);
100 }
101 } else if (dst_format == PP_VIDEOFRAME_FORMAT_YV12 ||
102 dst_format == PP_VIDEOFRAME_FORMAT_I420) {
103 static const size_t kPlanesOrder[][3] = {
104 { VideoFrame::kYPlane, VideoFrame::kVPlane, VideoFrame::kUPlane }, // YV12
105 { VideoFrame::kYPlane, VideoFrame::kUPlane, VideoFrame::kVPlane }, // I420
106 };
107 const int plane_order = (dst_format == PP_VIDEOFRAME_FORMAT_YV12) ? 0 : 1;
108 int dst_width = dst_size.width();
109 int dst_height = dst_size.height();
110 libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][0]),
111 src->stride(kPlanesOrder[plane_order][0]),
112 src->coded_size().width(),
113 src->coded_size().height(),
114 dst, dst_width, dst_width, dst_height,
115 kFilterMode);
116 dst += dst_width * dst_height;
117 const int src_halfwidth = (src->coded_size().width() + 1) >> 1;
118 const int src_halfheight = (src->coded_size().height() + 1) >> 1;
119 const int dst_halfwidth = (dst_width + 1) >> 1;
120 const int dst_halfheight = (dst_height + 1) >> 1;
121 libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][1]),
122 src->stride(kPlanesOrder[plane_order][1]),
123 src_halfwidth, src_halfheight,
124 dst, dst_halfwidth, dst_halfwidth, dst_halfheight,
125 kFilterMode);
126 dst += dst_halfwidth * dst_halfheight;
127 libyuv::ScalePlane(src->data(kPlanesOrder[plane_order][2]),
128 src->stride(kPlanesOrder[plane_order][2]),
129 src_halfwidth, src_halfheight,
130 dst, dst_halfwidth, dst_halfwidth, dst_halfheight,
131 kFilterMode);
132 } else {
133 NOTREACHED();
134 }
135 }
136
37 } // namespace 137 } // namespace
38 138
39 namespace content { 139 namespace content {
40 140
41 PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost( 141 PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost(
42 RendererPpapiHost* host, 142 RendererPpapiHost* host,
43 PP_Instance instance, 143 PP_Instance instance,
44 PP_Resource resource, 144 PP_Resource resource,
45 const blink::WebMediaStreamTrack& track) 145 const blink::WebMediaStreamTrack& track)
46 : PepperMediaStreamTrackHostBase(host, instance, resource), 146 : PepperMediaStreamTrackHostBase(host, instance, resource),
47 track_(track), 147 track_(track),
48 connected_(false), 148 connected_(false),
49 frame_format_(VideoFrame::UNKNOWN), 149 number_of_buffers_(kDefaultNumberOfBuffers),
150 source_frame_format_(PP_VIDEOFRAME_FORMAT_UNKNOWN),
151 plugin_frame_format_(PP_VIDEOFRAME_FORMAT_UNKNOWN),
50 frame_data_size_(0) { 152 frame_data_size_(0) {
51 DCHECK(!track_.isNull()); 153 DCHECK(!track_.isNull());
52 } 154 }
53 155
54 PepperMediaStreamVideoTrackHost::~PepperMediaStreamVideoTrackHost() { 156 PepperMediaStreamVideoTrackHost::~PepperMediaStreamVideoTrackHost() {
55 OnClose(); 157 OnClose();
56 } 158 }
57 159
160 void PepperMediaStreamVideoTrackHost::InitBuffers() {
161 gfx::Size size = GetTargetSize(source_frame_size_, plugin_frame_size_);
162 DCHECK(!size.IsEmpty());
163
164 PP_VideoFrame_Format format =
165 GetTargetFormat(source_frame_format_, plugin_frame_format_);
166 DCHECK_NE(format, PP_VIDEOFRAME_FORMAT_UNKNOWN);
167
168 if (format == PP_VIDEOFRAME_FORMAT_BGRA) {
169 frame_data_size_ = size.width() * size.height() * 4;
170 } else {
171 frame_data_size_ = VideoFrame::AllocationSize(FromPpapiFormat(format),
172 size);
173 }
174
175 DCHECK_GT(frame_data_size_, 0U);
176 int32_t buffer_size =
177 sizeof(ppapi::MediaStreamBuffer::Video) + frame_data_size_;
178 bool result = PepperMediaStreamTrackHostBase::InitBuffers(number_of_buffers_,
179 buffer_size);
180 CHECK(result);
181 }
182
58 void PepperMediaStreamVideoTrackHost::OnClose() { 183 void PepperMediaStreamVideoTrackHost::OnClose() {
59 if (connected_) { 184 if (connected_) {
60 MediaStreamVideoSink::RemoveFromVideoTrack(this, track_); 185 MediaStreamVideoSink::RemoveFromVideoTrack(this, track_);
61 connected_ = false; 186 connected_ = false;
62 } 187 }
63 } 188 }
64 189
65 void PepperMediaStreamVideoTrackHost::OnVideoFrame( 190 void PepperMediaStreamVideoTrackHost::OnVideoFrame(
66 const scoped_refptr<VideoFrame>& frame) { 191 const scoped_refptr<VideoFrame>& frame) {
67 DCHECK(frame); 192 DCHECK(frame);
68 // TODO(penghuang): Check |frame->end_of_stream()| and close the track. 193 // TODO(penghuang): Check |frame->end_of_stream()| and close the track.
69 PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format()); 194 PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format());
70 if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN) 195 if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN)
71 return; 196 return;
72 197
73 if (frame_size_ != frame->coded_size() || frame_format_ != frame->format()) { 198 if (source_frame_size_.IsEmpty()) {
74 frame_size_ = frame->coded_size(); 199 source_frame_size_ = frame->coded_size();
75 frame_format_ = frame->format(); 200 source_frame_format_ = ppformat;
76 // TODO(penghuang): Support changing |frame_size_| & |frame_format_| more 201 InitBuffers();
77 // than once.
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 } 202 }
85 203
86 int32_t index = buffer_manager()->DequeueBuffer(); 204 int32_t index = buffer_manager()->DequeueBuffer();
87 // Drop frames if the underlying buffer is full. 205 // Drop frames if the underlying buffer is full.
88 if (index < 0) 206 if (index < 0) {
207 DVLOG(1) << "A frame is dropped.";
89 return; 208 return;
209 }
90 210
91 // TODO(penghuang): support format conversion and size scaling. 211 CHECK(frame->coded_size() == source_frame_size_) << "Frame size is changed";
212 CHECK_EQ(ppformat, source_frame_format_) << "Frame format is changed.";
213
214 gfx::Size size = GetTargetSize(source_frame_size_, plugin_frame_size_);
215 PP_VideoFrame_Format format = GetTargetFormat(source_frame_format_,
216 plugin_frame_format_);
92 ppapi::MediaStreamBuffer::Video* buffer = 217 ppapi::MediaStreamBuffer::Video* buffer =
93 &(buffer_manager()->GetBufferPointer(index)->video); 218 &(buffer_manager()->GetBufferPointer(index)->video);
94 buffer->header.size = buffer_manager()->buffer_size(); 219 buffer->header.size = buffer_manager()->buffer_size();
95 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO; 220 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
96 buffer->timestamp = frame->GetTimestamp().InSecondsF(); 221 buffer->timestamp = frame->GetTimestamp().InSecondsF();
97 buffer->format = ppformat; 222 buffer->format = format;
98 buffer->size.width = frame->coded_size().width(); 223 buffer->size.width = size.width();
99 buffer->size.height = frame->coded_size().height(); 224 buffer->size.height = size.height();
100 buffer->data_size = frame_data_size_; 225 buffer->data_size = frame_data_size_;
101 226 ConvertFromMediaVideoFrame(frame, format, size, buffer->data);
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;
107 size_t num_planes = VideoFrame::NumPlanes(frame->format());
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); 227 SendEnqueueBufferMessageToPlugin(index);
121 } 228 }
122 229
123 void PepperMediaStreamVideoTrackHost::DidConnectPendingHostToResource() { 230 void PepperMediaStreamVideoTrackHost::DidConnectPendingHostToResource() {
124 if (!connected_) { 231 if (!connected_) {
125 MediaStreamVideoSink::AddToVideoTrack(this, track_); 232 MediaStreamVideoSink::AddToVideoTrack(this, track_);
126 connected_ = true; 233 connected_ = true;
127 } 234 }
128 } 235 }
129 236
237 int32_t PepperMediaStreamVideoTrackHost::OnResourceMessageReceived(
238 const IPC::Message& msg,
239 HostMessageContext* context) {
240 IPC_BEGIN_MESSAGE_MAP(PepperMediaStreamVideoTrackHost, msg)
241 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
242 PpapiHostMsg_MediaStreamVideoTrack_Configure,
243 OnHostMsgConfigure)
244 IPC_END_MESSAGE_MAP()
245 return PepperMediaStreamTrackHostBase::OnResourceMessageReceived(msg,
246 context);
247 }
248
249 int32_t PepperMediaStreamVideoTrackHost::OnHostMsgConfigure(
250 HostMessageContext* context,
251 const MediaStreamVideoTrackShared::Attributes& attributes) {
252 CHECK(MediaStreamVideoTrackShared::VerifyAttributes(attributes));
253
254 bool changed = false;
255 gfx::Size new_size(attributes.width, attributes.height);
256 if (GetTargetSize(source_frame_size_, plugin_frame_size_) !=
257 GetTargetSize(source_frame_size_, new_size)) {
258 changed = true;
259 }
260 plugin_frame_size_ = new_size;
261
262 int32_t buffers = attributes.buffers ?
263 std::min(kMaxNumberOfBuffers, attributes.buffers) :
264 kDefaultNumberOfBuffers;
265 if (buffers != number_of_buffers_)
266 changed = true;
267 number_of_buffers_ = buffers;
268
269 if (plugin_frame_format_ != attributes.format) {
Ronghua Wu (Left Chromium) 2014/02/19 21:16:24 nit: remove this line or do the same for size
Peng 2014/02/19 22:57:01 Done.
270 if (GetTargetFormat(source_frame_format_, plugin_frame_format_) !=
271 GetTargetFormat(source_frame_format_, attributes.format)) {
272 changed = true;
273 }
274 plugin_frame_format_ = attributes.format;
275 }
276
277 // If the first frame has been received, we will re-initialize buffers with
278 // new settings. Otherwise, we will initialize buffer when we receive
279 // the first frame, because plugin can only provide part of attributes
280 // which are not enough to initialize buffers.
281 if (changed && !source_frame_size_.IsEmpty())
282 InitBuffers();
283
284 context->reply_msg = PpapiPluginMsg_MediaStreamVideoTrack_ConfigureReply();
285 return PP_OK;
286 }
287
130 } // namespace content 288 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_media_stream_video_track_host.h ('k') | ppapi/api/ppb_media_stream_video_track.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698