OLD | NEW |
---|---|
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/media/webrtc/webrtc_video_capturer_adapter.h" | 5 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/memory/aligned_memory.h" | 8 #include "base/memory/aligned_memory.h" |
9 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
10 #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" | 10 #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" |
11 #include "media/base/timestamp_constants.h" | 11 #include "media/base/timestamp_constants.h" |
12 #include "media/base/video_frame.h" | |
13 #include "media/base/video_frame_pool.h" | |
14 #include "media/base/video_util.h" | 12 #include "media/base/video_util.h" |
15 #include "third_party/libyuv/include/libyuv/convert_from.h" | 13 #include "third_party/libyuv/include/libyuv/convert_from.h" |
16 #include "third_party/libyuv/include/libyuv/scale.h" | 14 #include "third_party/libyuv/include/libyuv/scale.h" |
17 #include "third_party/webrtc/common_video/include/video_frame_buffer.h" | 15 #include "third_party/webrtc/common_video/include/video_frame_buffer.h" |
18 #include "third_party/webrtc/common_video/rotation.h" | 16 #include "third_party/webrtc/common_video/rotation.h" |
19 #include "third_party/webrtc/media/base/videoframefactory.h" | |
20 #include "third_party/webrtc/media/engine/webrtcvideoframe.h" | 17 #include "third_party/webrtc/media/engine/webrtcvideoframe.h" |
21 | 18 |
22 namespace content { | 19 namespace content { |
23 namespace { | 20 namespace { |
24 | 21 |
25 // Empty method used for keeping a reference to the original media::VideoFrame. | 22 // Empty method used for keeping a reference to the original media::VideoFrame. |
26 // The reference to |frame| is kept in the closure that calls this method. | 23 // The reference to |frame| is kept in the closure that calls this method. |
27 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) { | 24 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) { |
28 } | 25 } |
29 | 26 |
30 } // anonymous namespace | 27 } // anonymous namespace |
31 | 28 |
32 // A cricket::VideoFrameFactory for media::VideoFrame. The purpose of this | |
33 // class is to avoid a premature frame copy. A media::VideoFrame is injected | |
34 // with SetFrame, and converted into a cricket::VideoFrame with | |
35 // CreateAliasedFrame. SetFrame should be called before CreateAliasedFrame | |
36 // for every frame. | |
37 class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory | |
38 : public cricket::VideoFrameFactory { | |
39 public: | |
40 void SetFrame(const scoped_refptr<media::VideoFrame>& frame) { | |
41 DCHECK(frame.get()); | |
42 // Create a CapturedFrame that only contains header information, not the | |
43 // actual pixel data. | |
44 captured_frame_.width = frame->natural_size().width(); | |
45 captured_frame_.height = frame->natural_size().height(); | |
46 captured_frame_.time_stamp = frame->timestamp().InMicroseconds() * | |
47 base::Time::kNanosecondsPerMicrosecond; | |
48 captured_frame_.pixel_height = 1; | |
49 captured_frame_.pixel_width = 1; | |
50 captured_frame_.rotation = webrtc::kVideoRotation_0; | |
51 captured_frame_.data = NULL; | |
52 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize; | |
53 captured_frame_.fourcc = static_cast<uint32_t>(cricket::FOURCC_ANY); | |
54 | |
55 frame_ = frame; | |
56 } | |
57 | |
58 void ReleaseFrame() { frame_ = NULL; } | |
59 | |
60 const cricket::CapturedFrame* GetCapturedFrame() const { | |
61 return &captured_frame_; | |
62 } | |
63 | |
64 cricket::VideoFrame* CreateAliasedFrame( | |
65 const cricket::CapturedFrame* input_frame, | |
66 int cropped_input_width, | |
67 int cropped_input_height, | |
68 int output_width, | |
69 int output_height) const override { | |
70 // Check that captured_frame is actually our frame. | |
71 DCHECK(input_frame == &captured_frame_); | |
72 DCHECK(frame_.get()); | |
73 | |
74 const int64_t timestamp_ns = frame_->timestamp().InMicroseconds() * | |
75 base::Time::kNanosecondsPerMicrosecond; | |
76 | |
77 // Return |frame_| directly if it is texture backed, because there is no | |
78 // cropping support for texture yet. See http://crbug/503653. | |
79 // Return |frame_| directly if it is GpuMemoryBuffer backed, as we want to | |
80 // keep the frame on native buffers. | |
81 if (frame_->HasTextures() || | |
82 frame_->storage_type() == | |
83 media::VideoFrame::STORAGE_GPU_MEMORY_BUFFERS) { | |
84 return new cricket::WebRtcVideoFrame( | |
85 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(frame_), | |
86 timestamp_ns, webrtc::kVideoRotation_0); | |
87 } | |
88 | |
89 // Create a centered cropped visible rect that preservers aspect ratio for | |
90 // cropped natural size. | |
91 gfx::Rect visible_rect = frame_->visible_rect(); | |
92 visible_rect.ClampToCenteredSize(gfx::Size( | |
93 visible_rect.width() * cropped_input_width / input_frame->width, | |
94 visible_rect.height() * cropped_input_height / input_frame->height)); | |
95 | |
96 const gfx::Size output_size(output_width, output_height); | |
97 scoped_refptr<media::VideoFrame> video_frame = | |
98 media::VideoFrame::WrapVideoFrame(frame_, frame_->format(), | |
99 visible_rect, output_size); | |
100 if (!video_frame) | |
101 return nullptr; | |
102 video_frame->AddDestructionObserver( | |
103 base::Bind(&ReleaseOriginalFrame, frame_)); | |
104 | |
105 // If no scaling is needed, return a wrapped version of |frame_| directly. | |
106 if (video_frame->natural_size() == video_frame->visible_rect().size()) { | |
107 return new cricket::WebRtcVideoFrame( | |
108 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(video_frame), | |
109 timestamp_ns, webrtc::kVideoRotation_0); | |
110 } | |
111 | |
112 // We need to scale the frame before we hand it over to cricket. | |
113 scoped_refptr<media::VideoFrame> scaled_frame = | |
114 scaled_frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, output_size, | |
115 gfx::Rect(output_size), output_size, | |
116 frame_->timestamp()); | |
117 libyuv::I420Scale(video_frame->visible_data(media::VideoFrame::kYPlane), | |
118 video_frame->stride(media::VideoFrame::kYPlane), | |
119 video_frame->visible_data(media::VideoFrame::kUPlane), | |
120 video_frame->stride(media::VideoFrame::kUPlane), | |
121 video_frame->visible_data(media::VideoFrame::kVPlane), | |
122 video_frame->stride(media::VideoFrame::kVPlane), | |
123 video_frame->visible_rect().width(), | |
124 video_frame->visible_rect().height(), | |
125 scaled_frame->data(media::VideoFrame::kYPlane), | |
126 scaled_frame->stride(media::VideoFrame::kYPlane), | |
127 scaled_frame->data(media::VideoFrame::kUPlane), | |
128 scaled_frame->stride(media::VideoFrame::kUPlane), | |
129 scaled_frame->data(media::VideoFrame::kVPlane), | |
130 scaled_frame->stride(media::VideoFrame::kVPlane), | |
131 output_width, output_height, libyuv::kFilterBilinear); | |
132 return new cricket::WebRtcVideoFrame( | |
133 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(scaled_frame), | |
134 timestamp_ns, webrtc::kVideoRotation_0); | |
135 } | |
136 | |
137 cricket::VideoFrame* CreateAliasedFrame( | |
138 const cricket::CapturedFrame* input_frame, | |
139 int output_width, | |
140 int output_height) const override { | |
141 return CreateAliasedFrame(input_frame, input_frame->width, | |
142 input_frame->height, output_width, output_height); | |
143 } | |
144 | |
145 private: | |
146 scoped_refptr<media::VideoFrame> frame_; | |
147 cricket::CapturedFrame captured_frame_; | |
148 // This is used only if scaling is needed. | |
149 mutable media::VideoFramePool scaled_frame_pool_; | |
150 }; | |
151 | |
152 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) | 29 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) |
153 : is_screencast_(is_screencast), | 30 : is_screencast_(is_screencast), |
154 running_(false) { | 31 running_(false) { |
155 thread_checker_.DetachFromThread(); | 32 thread_checker_.DetachFromThread(); |
156 // The base class takes ownership of the frame factory. | |
157 set_frame_factory(new MediaVideoFrameFactory); | |
158 } | 33 } |
159 | 34 |
160 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { | 35 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { |
161 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; | 36 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; |
162 } | 37 } |
163 | 38 |
164 cricket::CaptureState WebRtcVideoCapturerAdapter::Start( | 39 cricket::CaptureState WebRtcVideoCapturerAdapter::Start( |
165 const cricket::VideoFormat& capture_format) { | 40 const cricket::VideoFormat& capture_format) { |
166 DCHECK(thread_checker_.CalledOnValidThread()); | 41 DCHECK(thread_checker_.CalledOnValidThread()); |
167 DCHECK(!running_); | 42 DCHECK(!running_); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 // just use what is provided. | 86 // just use what is provided. |
212 // Use the desired format as the best format. | 87 // Use the desired format as the best format. |
213 best_format->width = desired.width; | 88 best_format->width = desired.width; |
214 best_format->height = desired.height; | 89 best_format->height = desired.height; |
215 best_format->fourcc = cricket::FOURCC_I420; | 90 best_format->fourcc = cricket::FOURCC_I420; |
216 best_format->interval = desired.interval; | 91 best_format->interval = desired.interval; |
217 return true; | 92 return true; |
218 } | 93 } |
219 | 94 |
220 void WebRtcVideoCapturerAdapter::OnFrameCaptured( | 95 void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
221 const scoped_refptr<media::VideoFrame>& video_frame) { | 96 const scoped_refptr<media::VideoFrame>& input_frame) { |
222 DCHECK(thread_checker_.CalledOnValidThread()); | 97 DCHECK(thread_checker_.CalledOnValidThread()); |
223 TRACE_EVENT0("video", "WebRtcVideoCapturerAdapter::OnFrameCaptured"); | 98 TRACE_EVENT0("video", "WebRtcVideoCapturerAdapter::OnFrameCaptured"); |
224 if (!(video_frame->IsMappable() && | 99 if (!(input_frame->IsMappable() && |
225 (video_frame->format() == media::PIXEL_FORMAT_I420 || | 100 (input_frame->format() == media::PIXEL_FORMAT_I420 || |
226 video_frame->format() == media::PIXEL_FORMAT_YV12 || | 101 input_frame->format() == media::PIXEL_FORMAT_YV12 || |
227 video_frame->format() == media::PIXEL_FORMAT_YV12A))) { | 102 input_frame->format() == media::PIXEL_FORMAT_YV12A))) { |
228 // Since connecting sources and sinks do not check the format, we need to | 103 // Since connecting sources and sinks do not check the format, we need to |
229 // just ignore formats that we can not handle. | 104 // just ignore formats that we can not handle. |
230 NOTREACHED(); | 105 NOTREACHED(); |
231 return; | 106 return; |
232 } | 107 } |
233 scoped_refptr<media::VideoFrame> frame = video_frame; | 108 scoped_refptr<media::VideoFrame> frame = input_frame; |
234 // Drop alpha channel since we do not support it yet. | 109 // Drop alpha channel since we do not support it yet. |
235 if (frame->format() == media::PIXEL_FORMAT_YV12A) | 110 if (frame->format() == media::PIXEL_FORMAT_YV12A) |
236 frame = media::WrapAsI420VideoFrame(video_frame); | 111 frame = media::WrapAsI420VideoFrame(input_frame); |
237 | 112 |
238 // Inject the frame via the VideoFrameFactory of base class. | 113 const int orig_width = frame->natural_size().width(); |
239 MediaVideoFrameFactory* media_video_frame_factory = | 114 const int orig_height = frame->natural_size().height(); |
240 reinterpret_cast<MediaVideoFrameFactory*>(frame_factory()); | 115 int adapted_width; |
241 media_video_frame_factory->SetFrame(frame); | 116 int adapted_height; |
117 // The VideoAdapter is only used for cpu-adaptation downscaling, no | |
118 // aspect changes. So we ignore these crop-related outputs. | |
119 int crop_width; | |
120 int crop_height; | |
121 int crop_x; | |
122 int crop_y; | |
123 int64_t translated_camera_time_us; | |
242 | 124 |
243 // This signals to libJingle that a new VideoFrame is available. | 125 if (!AdaptFrame(orig_width, orig_height, |
244 SignalFrameCaptured(this, media_video_frame_factory->GetCapturedFrame()); | 126 frame->timestamp().InMicroseconds(), |
127 rtc::TimeMicros(), | |
128 &adapted_width, &adapted_height, | |
129 &crop_width, &crop_height, &crop_x, &crop_y, | |
130 &translated_camera_time_us)) { | |
131 return; | |
132 } | |
245 | 133 |
246 media_video_frame_factory->ReleaseFrame(); // Release the frame ASAP. | 134 // Return |frame| directly if it is texture backed, because there is no |
135 // cropping support for texture yet. See http://crbug/503653. | |
136 // Return |frame| directly if it is GpuMemoryBuffer backed, as we want to | |
137 // keep the frame on native buffers. | |
138 if (frame->HasTextures() || | |
139 frame->storage_type() == | |
140 media::VideoFrame::STORAGE_GPU_MEMORY_BUFFERS) { | |
141 OnFrame(cricket::WebRtcVideoFrame( | |
142 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(frame), | |
143 webrtc::kVideoRotation_0, translated_camera_time_us), | |
perkj_chrome
2016/08/23 18:29:31
scary bug.
| |
144 orig_width, orig_height); | |
145 return; | |
146 } | |
147 | |
148 // Create a centered cropped visible rect that preservers aspect ratio for | |
149 // cropped natural size. | |
150 gfx::Rect visible_rect = frame->visible_rect(); | |
151 visible_rect.ClampToCenteredSize(gfx::Size( | |
152 visible_rect.width() * adapted_width / orig_width, | |
153 visible_rect.height() * adapted_height / orig_height)); | |
154 | |
155 const gfx::Size adapted_size(adapted_width, adapted_height); | |
156 scoped_refptr<media::VideoFrame> video_frame = | |
157 media::VideoFrame::WrapVideoFrame(frame, frame->format(), | |
158 visible_rect, adapted_size); | |
159 if (!video_frame) | |
160 return; | |
161 | |
162 video_frame->AddDestructionObserver(base::Bind(&ReleaseOriginalFrame, frame)); | |
163 | |
164 // If no scaling is needed, return a wrapped version of |frame| directly. | |
165 if (video_frame->natural_size() == video_frame->visible_rect().size()) { | |
166 OnFrame(cricket::WebRtcVideoFrame( | |
167 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(video_frame), | |
168 webrtc::kVideoRotation_0, translated_camera_time_us), | |
169 orig_width, orig_height); | |
170 return; | |
171 } | |
172 | |
173 // We need to scale the frame before we hand it over to webrtc. | |
174 scoped_refptr<media::VideoFrame> scaled_frame = | |
175 scaled_frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, adapted_size, | |
176 gfx::Rect(adapted_size), adapted_size, | |
177 frame->timestamp()); | |
178 libyuv::I420Scale(video_frame->visible_data(media::VideoFrame::kYPlane), | |
179 video_frame->stride(media::VideoFrame::kYPlane), | |
180 video_frame->visible_data(media::VideoFrame::kUPlane), | |
181 video_frame->stride(media::VideoFrame::kUPlane), | |
182 video_frame->visible_data(media::VideoFrame::kVPlane), | |
183 video_frame->stride(media::VideoFrame::kVPlane), | |
184 video_frame->visible_rect().width(), | |
185 video_frame->visible_rect().height(), | |
186 scaled_frame->data(media::VideoFrame::kYPlane), | |
187 scaled_frame->stride(media::VideoFrame::kYPlane), | |
188 scaled_frame->data(media::VideoFrame::kUPlane), | |
189 scaled_frame->stride(media::VideoFrame::kUPlane), | |
190 scaled_frame->data(media::VideoFrame::kVPlane), | |
191 scaled_frame->stride(media::VideoFrame::kVPlane), | |
192 adapted_width, adapted_height, libyuv::kFilterBilinear); | |
193 | |
194 OnFrame(cricket::WebRtcVideoFrame( | |
195 new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(scaled_frame), | |
196 webrtc::kVideoRotation_0, translated_camera_time_us), | |
197 orig_width, orig_height); | |
247 } | 198 } |
248 | 199 |
249 } // namespace content | 200 } // namespace content |
OLD | NEW |