henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 1 | /* |
kjellander | 1afca73 | 2016-02-07 20:46:45 -0800 | [diff] [blame] | 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 3 | * |
kjellander | 1afca73 | 2016-02-07 20:46:45 -0800 | [diff] [blame] | 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 |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 9 | */ |
| 10 | |
kjellander@webrtc.org | 5ad1297 | 2016-02-12 06:39:40 +0100 | [diff] [blame] | 11 | #include "webrtc/media/engine/webrtcvideoframe.h" |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 12 | |
| 13 | #include "libyuv/convert.h" |
buildbot@webrtc.org | a09a999 | 2014-08-13 17:26:08 +0000 | [diff] [blame] | 14 | #include "webrtc/base/logging.h" |
kjellander | a96e2d7 | 2016-02-04 23:52:28 -0800 | [diff] [blame] | 15 | #include "webrtc/media/base/videocapturer.h" |
| 16 | #include "webrtc/media/base/videocommon.h" |
magjed@webrtc.org | e575e9c | 2014-12-14 11:09:23 +0000 | [diff] [blame] | 17 | #include "webrtc/video_frame.h" |
| 18 | |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 19 | using webrtc::kYPlane; |
| 20 | using webrtc::kUPlane; |
| 21 | using webrtc::kVPlane; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 22 | |
| 23 | namespace cricket { |
| 24 | |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 25 | WebRtcVideoFrame::WebRtcVideoFrame() |
| 26 | : timestamp_us_(0), 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) {} |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 35 | |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 36 | WebRtcVideoFrame::WebRtcVideoFrame( |
| 37 | const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, |
Guo-wei Shieh | 64c1e8c | 2015-04-01 15:33:06 -0700 | [diff] [blame] | 38 | int64_t time_stamp_ns, |
| 39 | webrtc::VideoRotation rotation) |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 40 | : WebRtcVideoFrame(buffer, |
| 41 | rotation, |
| 42 | time_stamp_ns / rtc::kNumNanosecsPerMicrosec) {} |
Guo-wei Shieh | 64c1e8c | 2015-04-01 15:33:06 -0700 | [diff] [blame] | 43 | |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 44 | WebRtcVideoFrame::~WebRtcVideoFrame() {} |
| 45 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 46 | bool WebRtcVideoFrame::Init(uint32_t format, |
guoweis@webrtc.org | 6c930c7 | 2015-02-09 01:28:12 +0000 | [diff] [blame] | 47 | int w, |
| 48 | int h, |
| 49 | int dw, |
| 50 | int dh, |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 51 | uint8_t* sample, |
guoweis@webrtc.org | 6c930c7 | 2015-02-09 01:28:12 +0000 | [diff] [blame] | 52 | size_t sample_size, |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 53 | int64_t time_stamp_ns, |
guoweis@webrtc.org | 6c930c7 | 2015-02-09 01:28:12 +0000 | [diff] [blame] | 54 | webrtc::VideoRotation rotation) { |
nisse | 8b1e431 | 2016-01-18 01:46:27 -0800 | [diff] [blame] | 55 | return Reset(format, w, h, dw, dh, sample, sample_size, |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 56 | time_stamp_ns / rtc::kNumNanosecsPerMicrosec, rotation, |
perkj@webrtc.org | 1d82813 | 2015-03-03 06:44:06 +0000 | [diff] [blame] | 57 | true /*apply_rotation*/); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 58 | } |
| 59 | |
perkj@webrtc.org | 1d82813 | 2015-03-03 06:44:06 +0000 | [diff] [blame] | 60 | bool WebRtcVideoFrame::Init(const CapturedFrame* frame, int dw, int dh, |
| 61 | bool apply_rotation) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 62 | return Reset(frame->fourcc, frame->width, frame->height, dw, dh, |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 63 | static_cast<uint8_t*>(frame->data), frame->data_size, |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 64 | frame->time_stamp / rtc::kNumNanosecsPerMicrosec, |
perkj | 7755e20 | 2015-11-19 12:02:21 -0800 | [diff] [blame] | 65 | frame->rotation, apply_rotation); |
magjed | b09b660 | 2015-10-01 03:02:44 -0700 | [diff] [blame] | 66 | } |
| 67 | |
nisse | 8b1e431 | 2016-01-18 01:46:27 -0800 | [diff] [blame] | 68 | bool WebRtcVideoFrame::InitToBlack(int w, int h, |
| 69 | int64_t time_stamp_ns) { |
| 70 | InitToEmptyBuffer(w, h, time_stamp_ns); |
thorcarpenter@google.com | 88d14f4 | 2014-11-22 01:04:26 +0000 | [diff] [blame] | 71 | return SetToBlack(); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 72 | } |
| 73 | |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 74 | int WebRtcVideoFrame::width() const { |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 75 | return video_frame_buffer_ ? video_frame_buffer_->width() : 0; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 76 | } |
| 77 | |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 78 | int WebRtcVideoFrame::height() const { |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 79 | return video_frame_buffer_ ? video_frame_buffer_->height() : 0; |
| 80 | } |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 81 | |
tommi@webrtc.org | 1f94407 | 2015-03-04 17:33:55 +0000 | [diff] [blame] | 82 | bool WebRtcVideoFrame::IsExclusive() const { |
Niels Möller | 47fe34c | 2016-04-18 13:02:59 +0200 | [diff] [blame] | 83 | return video_frame_buffer_->IsMutable(); |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | void* WebRtcVideoFrame::GetNativeHandle() const { |
| 87 | return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr; |
| 88 | } |
| 89 | |
nisse | 0565451 | 2016-04-29 02:56:00 -0700 | [diff] [blame] | 90 | const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& |
nisse | f386876 | 2016-04-13 03:29:16 -0700 | [diff] [blame] | 91 | WebRtcVideoFrame::video_frame_buffer() const { |
magjed@webrtc.org | afdd5dd | 2015-03-12 13:11:25 +0000 | [diff] [blame] | 92 | return video_frame_buffer_; |
| 93 | } |
| 94 | |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 95 | VideoFrame* WebRtcVideoFrame::Copy() const { |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 96 | return new WebRtcVideoFrame(video_frame_buffer_, rotation_, timestamp_us_); |
magjed@webrtc.org | 50b2295 | 2015-03-02 10:03:47 +0000 | [diff] [blame] | 97 | } |
| 98 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 99 | size_t WebRtcVideoFrame::ConvertToRgbBuffer(uint32_t to_fourcc, |
| 100 | uint8_t* buffer, |
| 101 | size_t size, |
| 102 | int stride_rgb) const { |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 103 | RTC_CHECK(video_frame_buffer_); |
| 104 | RTC_CHECK(video_frame_buffer_->native_handle() == nullptr); |
magjed@webrtc.org | bdcf38c | 2014-11-21 10:53:00 +0000 | [diff] [blame] | 105 | return VideoFrame::ConvertToRgbBuffer(to_fourcc, buffer, size, stride_rgb); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 106 | } |
| 107 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 108 | bool WebRtcVideoFrame::Reset(uint32_t format, |
guoweis@webrtc.org | 6c930c7 | 2015-02-09 01:28:12 +0000 | [diff] [blame] | 109 | int w, |
| 110 | int h, |
| 111 | int dw, |
| 112 | int dh, |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 113 | uint8_t* sample, |
guoweis@webrtc.org | 6c930c7 | 2015-02-09 01:28:12 +0000 | [diff] [blame] | 114 | size_t sample_size, |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 115 | int64_t timestamp_us, |
perkj@webrtc.org | 1d82813 | 2015-03-03 06:44:06 +0000 | [diff] [blame] | 116 | webrtc::VideoRotation rotation, |
| 117 | bool apply_rotation) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 118 | if (!Validate(format, w, h, sample, sample_size)) { |
| 119 | return false; |
| 120 | } |
| 121 | // Translate aliases to standard enums (e.g., IYUV -> I420). |
| 122 | format = CanonicalFourCC(format); |
| 123 | |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 124 | // Set up a new buffer. |
| 125 | // TODO(fbarchard): Support lazy allocation. |
| 126 | int new_width = dw; |
| 127 | int new_height = dh; |
perkj@webrtc.org | 1d82813 | 2015-03-03 06:44:06 +0000 | [diff] [blame] | 128 | // If rotated swap width, height. |
| 129 | if (apply_rotation && (rotation == 90 || rotation == 270)) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 130 | new_width = dh; |
| 131 | new_height = dw; |
| 132 | } |
| 133 | |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 134 | InitToEmptyBuffer(new_width, new_height); |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 135 | rotation_ = apply_rotation ? webrtc::kVideoRotation_0 : rotation; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 136 | |
| 137 | int horiz_crop = ((w - dw) / 2) & ~1; |
| 138 | // ARGB on Windows has negative height. |
| 139 | // The sample's layout in memory is normal, so just correct crop. |
| 140 | int vert_crop = ((abs(h) - dh) / 2) & ~1; |
| 141 | // Conversion functions expect negative height to flip the image. |
| 142 | int idh = (h < 0) ? -dh : dh; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 143 | int r = libyuv::ConvertToI420( |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 144 | sample, sample_size, |
nisse | 0565451 | 2016-04-29 02:56:00 -0700 | [diff] [blame] | 145 | video_frame_buffer_->MutableDataY(), |
| 146 | video_frame_buffer_->StrideY(), |
| 147 | video_frame_buffer_->MutableDataU(), |
| 148 | video_frame_buffer_->StrideU(), |
| 149 | video_frame_buffer_->MutableDataV(), |
| 150 | video_frame_buffer_->StrideV(), |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 151 | horiz_crop, vert_crop, |
| 152 | w, h, |
| 153 | dw, idh, |
perkj@webrtc.org | 1d82813 | 2015-03-03 06:44:06 +0000 | [diff] [blame] | 154 | static_cast<libyuv::RotationMode>( |
| 155 | apply_rotation ? rotation : webrtc::kVideoRotation_0), |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 156 | format); |
| 157 | if (r) { |
| 158 | LOG(LS_ERROR) << "Error parsing format: " << GetFourccName(format) |
| 159 | << " return code : " << r; |
| 160 | return false; |
| 161 | } |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 162 | timestamp_us_ = timestamp_us; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 163 | return true; |
| 164 | } |
| 165 | |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 166 | VideoFrame* WebRtcVideoFrame::CreateEmptyFrame(int w, |
| 167 | int h, |
| 168 | int64_t timestamp_us) const { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 169 | WebRtcVideoFrame* frame = new WebRtcVideoFrame(); |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 170 | frame->InitToEmptyBuffer(w, h, rtc::kNumNanosecsPerMicrosec * timestamp_us); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 171 | return frame; |
| 172 | } |
| 173 | |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 174 | void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h) { |
| 175 | video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h); |
| 176 | rotation_ = webrtc::kVideoRotation_0; |
| 177 | } |
| 178 | |
nisse | 8b1e431 | 2016-01-18 01:46:27 -0800 | [diff] [blame] | 179 | void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h, |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 180 | int64_t time_stamp_ns) { |
| 181 | video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h); |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 182 | SetTimeStamp(time_stamp_ns); |
magjed@webrtc.org | 2386d6d | 2015-03-05 14:03:08 +0000 | [diff] [blame] | 183 | rotation_ = webrtc::kVideoRotation_0; |
magjed@webrtc.org | e575e9c | 2014-12-14 11:09:23 +0000 | [diff] [blame] | 184 | } |
| 185 | |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 186 | const VideoFrame* WebRtcVideoFrame::GetCopyWithRotationApplied() const { |
| 187 | // If the frame is not rotated, the caller should reuse this frame instead of |
| 188 | // making a redundant copy. |
nisse | f386876 | 2016-04-13 03:29:16 -0700 | [diff] [blame] | 189 | if (rotation() == webrtc::kVideoRotation_0) { |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 190 | return this; |
| 191 | } |
| 192 | |
| 193 | // If the video frame is backed up by a native handle, it resides in the GPU |
| 194 | // memory which we can't rotate here. The assumption is that the renderers |
| 195 | // which uses GPU to render should be able to rotate themselves. |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 196 | RTC_DCHECK(!GetNativeHandle()); |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 197 | |
| 198 | if (rotated_frame_) { |
| 199 | return rotated_frame_.get(); |
| 200 | } |
| 201 | |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 202 | int orig_width = width(); |
| 203 | int orig_height = height(); |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 204 | |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 205 | int rotated_width = orig_width; |
| 206 | int rotated_height = orig_height; |
nisse | f386876 | 2016-04-13 03:29:16 -0700 | [diff] [blame] | 207 | if (rotation() == webrtc::kVideoRotation_90 || |
| 208 | rotation() == webrtc::kVideoRotation_270) { |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 209 | rotated_width = orig_height; |
| 210 | rotated_height = orig_width; |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 211 | } |
| 212 | |
nisse | b17712f | 2016-04-14 02:29:29 -0700 | [diff] [blame] | 213 | rotated_frame_.reset( |
| 214 | CreateEmptyFrame(rotated_width, rotated_height, timestamp_us_)); |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 215 | |
| 216 | // TODO(guoweis): Add a function in webrtc_libyuv.cc to convert from |
| 217 | // VideoRotation to libyuv::RotationMode. |
| 218 | int ret = libyuv::I420Rotate( |
nisse | 0565451 | 2016-04-29 02:56:00 -0700 | [diff] [blame] | 219 | video_frame_buffer_->DataY(), video_frame_buffer_->StrideY(), |
| 220 | video_frame_buffer_->DataU(), video_frame_buffer_->StrideU(), |
| 221 | video_frame_buffer_->DataV(), video_frame_buffer_->StrideV(), |
| 222 | rotated_frame_->video_frame_buffer()->MutableDataY(), |
| 223 | rotated_frame_->video_frame_buffer()->StrideY(), |
| 224 | rotated_frame_->video_frame_buffer()->MutableDataU(), |
| 225 | rotated_frame_->video_frame_buffer()->StrideU(), |
| 226 | rotated_frame_->video_frame_buffer()->MutableDataV(), |
| 227 | rotated_frame_->video_frame_buffer()->StrideV(), |
nisse | 71a0c2f | 2016-04-04 00:57:29 -0700 | [diff] [blame] | 228 | orig_width, orig_height, |
nisse | f386876 | 2016-04-13 03:29:16 -0700 | [diff] [blame] | 229 | static_cast<libyuv::RotationMode>(rotation())); |
guoweis@webrtc.org | 00c509a | 2015-03-12 21:37:26 +0000 | [diff] [blame] | 230 | if (ret == 0) { |
| 231 | return rotated_frame_.get(); |
| 232 | } |
| 233 | return nullptr; |
| 234 | } |
| 235 | |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 236 | } // namespace cricket |