OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/media/engine/webrtcvideoframe.h" | 11 #include "webrtc/media/engine/webrtcvideoframe.h" |
12 | 12 |
13 #include "libyuv/convert.h" | 13 #include "libyuv/convert.h" |
14 #include "webrtc/base/logging.h" | 14 #include "webrtc/base/logging.h" |
15 #include "webrtc/media/base/videocapturer.h" | 15 #include "webrtc/media/base/videocapturer.h" |
16 #include "webrtc/media/base/videocommon.h" | 16 #include "webrtc/media/base/videocommon.h" |
17 #include "webrtc/video_frame.h" | 17 #include "webrtc/video_frame.h" |
18 | 18 |
19 using webrtc::kYPlane; | 19 using webrtc::kYPlane; |
20 using webrtc::kUPlane; | 20 using webrtc::kUPlane; |
21 using webrtc::kVPlane; | 21 using webrtc::kVPlane; |
22 | 22 |
23 namespace cricket { | 23 namespace cricket { |
24 | 24 |
25 WebRtcVideoFrame::WebRtcVideoFrame(): | 25 WebRtcVideoFrame::WebRtcVideoFrame() |
26 time_stamp_ns_(0), | 26 : timestamp_us_(0), rotation_(webrtc::kVideoRotation_0) {} |
27 rotation_(webrtc::kVideoRotation_0) {} | 27 |
| 28 WebRtcVideoFrame::WebRtcVideoFrame( |
| 29 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, |
| 30 webrtc::VideoRotation rotation, |
| 31 int64_t timestamp_us) |
| 32 : video_frame_buffer_(buffer), |
| 33 timestamp_us_(timestamp_us), |
| 34 rotation_(rotation) {} |
28 | 35 |
29 WebRtcVideoFrame::WebRtcVideoFrame( | 36 WebRtcVideoFrame::WebRtcVideoFrame( |
30 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, | 37 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, |
31 int64_t time_stamp_ns, | 38 int64_t time_stamp_ns, |
32 webrtc::VideoRotation rotation) | 39 webrtc::VideoRotation rotation) |
33 : video_frame_buffer_(buffer), | 40 : WebRtcVideoFrame(buffer, |
34 time_stamp_ns_(time_stamp_ns), | 41 rotation, |
35 rotation_(rotation) { | 42 time_stamp_ns / rtc::kNumNanosecsPerMicrosec) {} |
36 } | |
37 | 43 |
38 WebRtcVideoFrame::~WebRtcVideoFrame() {} | 44 WebRtcVideoFrame::~WebRtcVideoFrame() {} |
39 | 45 |
40 bool WebRtcVideoFrame::Init(uint32_t format, | 46 bool WebRtcVideoFrame::Init(uint32_t format, |
41 int w, | 47 int w, |
42 int h, | 48 int h, |
43 int dw, | 49 int dw, |
44 int dh, | 50 int dh, |
45 uint8_t* sample, | 51 uint8_t* sample, |
46 size_t sample_size, | 52 size_t sample_size, |
47 int64_t time_stamp_ns, | 53 int64_t time_stamp_ns, |
48 webrtc::VideoRotation rotation) { | 54 webrtc::VideoRotation rotation) { |
49 return Reset(format, w, h, dw, dh, sample, sample_size, | 55 return Reset(format, w, h, dw, dh, sample, sample_size, |
50 time_stamp_ns, rotation, | 56 time_stamp_ns / rtc::kNumNanosecsPerMicrosec, rotation, |
51 true /*apply_rotation*/); | 57 true /*apply_rotation*/); |
52 } | 58 } |
53 | 59 |
54 bool WebRtcVideoFrame::Init(const CapturedFrame* frame, int dw, int dh, | 60 bool WebRtcVideoFrame::Init(const CapturedFrame* frame, int dw, int dh, |
55 bool apply_rotation) { | 61 bool apply_rotation) { |
56 return Reset(frame->fourcc, frame->width, frame->height, dw, dh, | 62 return Reset(frame->fourcc, frame->width, frame->height, dw, dh, |
57 static_cast<uint8_t*>(frame->data), frame->data_size, | 63 static_cast<uint8_t*>(frame->data), frame->data_size, |
58 frame->time_stamp, | 64 frame->time_stamp / rtc::kNumNanosecsPerMicrosec, |
59 frame->rotation, apply_rotation); | 65 frame->rotation, apply_rotation); |
60 } | 66 } |
61 | 67 |
62 bool WebRtcVideoFrame::InitToBlack(int w, int h, | 68 bool WebRtcVideoFrame::InitToBlack(int w, int h, |
63 int64_t time_stamp_ns) { | 69 int64_t time_stamp_ns) { |
64 InitToEmptyBuffer(w, h, time_stamp_ns); | 70 InitToEmptyBuffer(w, h, time_stamp_ns); |
65 return SetToBlack(); | 71 return SetToBlack(); |
66 } | 72 } |
67 | 73 |
68 int WebRtcVideoFrame::width() const { | 74 int WebRtcVideoFrame::width() const { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 void* WebRtcVideoFrame::GetNativeHandle() const { | 125 void* WebRtcVideoFrame::GetNativeHandle() const { |
120 return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr; | 126 return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr; |
121 } | 127 } |
122 | 128 |
123 rtc::scoped_refptr<webrtc::VideoFrameBuffer> | 129 rtc::scoped_refptr<webrtc::VideoFrameBuffer> |
124 WebRtcVideoFrame::video_frame_buffer() const { | 130 WebRtcVideoFrame::video_frame_buffer() const { |
125 return video_frame_buffer_; | 131 return video_frame_buffer_; |
126 } | 132 } |
127 | 133 |
128 VideoFrame* WebRtcVideoFrame::Copy() const { | 134 VideoFrame* WebRtcVideoFrame::Copy() const { |
129 WebRtcVideoFrame* new_frame = new WebRtcVideoFrame( | 135 return new WebRtcVideoFrame(video_frame_buffer_, rotation_, timestamp_us_); |
130 video_frame_buffer_, time_stamp_ns_, rotation_); | |
131 return new_frame; | |
132 } | 136 } |
133 | 137 |
134 size_t WebRtcVideoFrame::ConvertToRgbBuffer(uint32_t to_fourcc, | 138 size_t WebRtcVideoFrame::ConvertToRgbBuffer(uint32_t to_fourcc, |
135 uint8_t* buffer, | 139 uint8_t* buffer, |
136 size_t size, | 140 size_t size, |
137 int stride_rgb) const { | 141 int stride_rgb) const { |
138 RTC_CHECK(video_frame_buffer_); | 142 RTC_CHECK(video_frame_buffer_); |
139 RTC_CHECK(video_frame_buffer_->native_handle() == nullptr); | 143 RTC_CHECK(video_frame_buffer_->native_handle() == nullptr); |
140 return VideoFrame::ConvertToRgbBuffer(to_fourcc, buffer, size, stride_rgb); | 144 return VideoFrame::ConvertToRgbBuffer(to_fourcc, buffer, size, stride_rgb); |
141 } | 145 } |
142 | 146 |
143 bool WebRtcVideoFrame::Reset(uint32_t format, | 147 bool WebRtcVideoFrame::Reset(uint32_t format, |
144 int w, | 148 int w, |
145 int h, | 149 int h, |
146 int dw, | 150 int dw, |
147 int dh, | 151 int dh, |
148 uint8_t* sample, | 152 uint8_t* sample, |
149 size_t sample_size, | 153 size_t sample_size, |
150 int64_t time_stamp_ns, | 154 int64_t timestamp_us, |
151 webrtc::VideoRotation rotation, | 155 webrtc::VideoRotation rotation, |
152 bool apply_rotation) { | 156 bool apply_rotation) { |
153 if (!Validate(format, w, h, sample, sample_size)) { | 157 if (!Validate(format, w, h, sample, sample_size)) { |
154 return false; | 158 return false; |
155 } | 159 } |
156 // Translate aliases to standard enums (e.g., IYUV -> I420). | 160 // Translate aliases to standard enums (e.g., IYUV -> I420). |
157 format = CanonicalFourCC(format); | 161 format = CanonicalFourCC(format); |
158 | 162 |
159 // Set up a new buffer. | 163 // Set up a new buffer. |
160 // TODO(fbarchard): Support lazy allocation. | 164 // TODO(fbarchard): Support lazy allocation. |
161 int new_width = dw; | 165 int new_width = dw; |
162 int new_height = dh; | 166 int new_height = dh; |
163 // If rotated swap width, height. | 167 // If rotated swap width, height. |
164 if (apply_rotation && (rotation == 90 || rotation == 270)) { | 168 if (apply_rotation && (rotation == 90 || rotation == 270)) { |
165 new_width = dh; | 169 new_width = dh; |
166 new_height = dw; | 170 new_height = dw; |
167 } | 171 } |
168 | 172 |
169 InitToEmptyBuffer(new_width, new_height, | 173 InitToEmptyBuffer(new_width, new_height); |
170 time_stamp_ns); | |
171 rotation_ = apply_rotation ? webrtc::kVideoRotation_0 : rotation; | 174 rotation_ = apply_rotation ? webrtc::kVideoRotation_0 : rotation; |
172 | 175 |
173 int horiz_crop = ((w - dw) / 2) & ~1; | 176 int horiz_crop = ((w - dw) / 2) & ~1; |
174 // ARGB on Windows has negative height. | 177 // ARGB on Windows has negative height. |
175 // The sample's layout in memory is normal, so just correct crop. | 178 // The sample's layout in memory is normal, so just correct crop. |
176 int vert_crop = ((abs(h) - dh) / 2) & ~1; | 179 int vert_crop = ((abs(h) - dh) / 2) & ~1; |
177 // Conversion functions expect negative height to flip the image. | 180 // Conversion functions expect negative height to flip the image. |
178 int idh = (h < 0) ? -dh : dh; | 181 int idh = (h < 0) ? -dh : dh; |
179 int r = libyuv::ConvertToI420( | 182 int r = libyuv::ConvertToI420( |
180 sample, sample_size, | 183 sample, sample_size, |
181 GetYPlane(), GetYPitch(), | 184 GetYPlane(), GetYPitch(), |
182 GetUPlane(), GetUPitch(), | 185 GetUPlane(), GetUPitch(), |
183 GetVPlane(), GetVPitch(), | 186 GetVPlane(), GetVPitch(), |
184 horiz_crop, vert_crop, | 187 horiz_crop, vert_crop, |
185 w, h, | 188 w, h, |
186 dw, idh, | 189 dw, idh, |
187 static_cast<libyuv::RotationMode>( | 190 static_cast<libyuv::RotationMode>( |
188 apply_rotation ? rotation : webrtc::kVideoRotation_0), | 191 apply_rotation ? rotation : webrtc::kVideoRotation_0), |
189 format); | 192 format); |
190 if (r) { | 193 if (r) { |
191 LOG(LS_ERROR) << "Error parsing format: " << GetFourccName(format) | 194 LOG(LS_ERROR) << "Error parsing format: " << GetFourccName(format) |
192 << " return code : " << r; | 195 << " return code : " << r; |
193 return false; | 196 return false; |
194 } | 197 } |
| 198 timestamp_us_ = timestamp_us; |
195 return true; | 199 return true; |
196 } | 200 } |
197 | 201 |
198 VideoFrame* WebRtcVideoFrame::CreateEmptyFrame( | 202 VideoFrame* WebRtcVideoFrame::CreateEmptyFrame(int w, |
199 int w, int h, | 203 int h, |
200 int64_t time_stamp_ns) const { | 204 int64_t timestamp_us) const { |
201 WebRtcVideoFrame* frame = new WebRtcVideoFrame(); | 205 WebRtcVideoFrame* frame = new WebRtcVideoFrame(); |
202 frame->InitToEmptyBuffer(w, h, time_stamp_ns); | 206 frame->InitToEmptyBuffer(w, h, rtc::kNumNanosecsPerMicrosec * timestamp_us); |
203 return frame; | 207 return frame; |
204 } | 208 } |
205 | 209 |
| 210 void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h) { |
| 211 video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h); |
| 212 rotation_ = webrtc::kVideoRotation_0; |
| 213 } |
| 214 |
206 void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h, | 215 void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h, |
207 int64_t time_stamp_ns) { | 216 int64_t time_stamp_ns) { |
208 video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h); | 217 video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h); |
209 time_stamp_ns_ = time_stamp_ns; | 218 SetTimeStamp(time_stamp_ns); |
210 rotation_ = webrtc::kVideoRotation_0; | 219 rotation_ = webrtc::kVideoRotation_0; |
211 } | 220 } |
212 | 221 |
213 const VideoFrame* WebRtcVideoFrame::GetCopyWithRotationApplied() const { | 222 const VideoFrame* WebRtcVideoFrame::GetCopyWithRotationApplied() const { |
214 // If the frame is not rotated, the caller should reuse this frame instead of | 223 // If the frame is not rotated, the caller should reuse this frame instead of |
215 // making a redundant copy. | 224 // making a redundant copy. |
216 if (rotation() == webrtc::kVideoRotation_0) { | 225 if (rotation() == webrtc::kVideoRotation_0) { |
217 return this; | 226 return this; |
218 } | 227 } |
219 | 228 |
(...skipping 10 matching lines...) Expand all Loading... |
230 int orig_height = height(); | 239 int orig_height = height(); |
231 | 240 |
232 int rotated_width = orig_width; | 241 int rotated_width = orig_width; |
233 int rotated_height = orig_height; | 242 int rotated_height = orig_height; |
234 if (rotation() == webrtc::kVideoRotation_90 || | 243 if (rotation() == webrtc::kVideoRotation_90 || |
235 rotation() == webrtc::kVideoRotation_270) { | 244 rotation() == webrtc::kVideoRotation_270) { |
236 rotated_width = orig_height; | 245 rotated_width = orig_height; |
237 rotated_height = orig_width; | 246 rotated_height = orig_width; |
238 } | 247 } |
239 | 248 |
240 rotated_frame_.reset(CreateEmptyFrame(rotated_width, rotated_height, | 249 rotated_frame_.reset( |
241 GetTimeStamp())); | 250 CreateEmptyFrame(rotated_width, rotated_height, timestamp_us_)); |
242 | 251 |
243 // TODO(guoweis): Add a function in webrtc_libyuv.cc to convert from | 252 // TODO(guoweis): Add a function in webrtc_libyuv.cc to convert from |
244 // VideoRotation to libyuv::RotationMode. | 253 // VideoRotation to libyuv::RotationMode. |
245 int ret = libyuv::I420Rotate( | 254 int ret = libyuv::I420Rotate( |
246 GetYPlane(), GetYPitch(), GetUPlane(), GetUPitch(), GetVPlane(), | 255 GetYPlane(), GetYPitch(), GetUPlane(), GetUPitch(), GetVPlane(), |
247 GetVPitch(), rotated_frame_->GetYPlane(), rotated_frame_->GetYPitch(), | 256 GetVPitch(), rotated_frame_->GetYPlane(), rotated_frame_->GetYPitch(), |
248 rotated_frame_->GetUPlane(), rotated_frame_->GetUPitch(), | 257 rotated_frame_->GetUPlane(), rotated_frame_->GetUPitch(), |
249 rotated_frame_->GetVPlane(), rotated_frame_->GetVPitch(), | 258 rotated_frame_->GetVPlane(), rotated_frame_->GetVPitch(), |
250 orig_width, orig_height, | 259 orig_width, orig_height, |
251 static_cast<libyuv::RotationMode>(rotation())); | 260 static_cast<libyuv::RotationMode>(rotation())); |
252 if (ret == 0) { | 261 if (ret == 0) { |
253 return rotated_frame_.get(); | 262 return rotated_frame_.get(); |
254 } | 263 } |
255 return nullptr; | 264 return nullptr; |
256 } | 265 } |
257 | 266 |
258 } // namespace cricket | 267 } // namespace cricket |
OLD | NEW |