blob: cda00275f70d2d87b6a20105fa14a474a8459e08 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * 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.org28e20752013-07-10 00:45:36 +00009 */
10
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010011#include "webrtc/media/engine/webrtcvideoframe.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
13#include "libyuv/convert.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000014#include "webrtc/base/logging.h"
kjellandera96e2d72016-02-04 23:52:28 -080015#include "webrtc/media/base/videocapturer.h"
16#include "webrtc/media/base/videocommon.h"
magjed@webrtc.orge575e9c2014-12-14 11:09:23 +000017#include "webrtc/video_frame.h"
18
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000019using webrtc::kYPlane;
20using webrtc::kUPlane;
21using webrtc::kVPlane;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000022
23namespace cricket {
24
nisseb17712f2016-04-14 02:29:29 -070025WebRtcVideoFrame::WebRtcVideoFrame()
26 : timestamp_us_(0), rotation_(webrtc::kVideoRotation_0) {}
27
28WebRtcVideoFrame::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.org28e20752013-07-10 00:45:36 +000035
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000036WebRtcVideoFrame::WebRtcVideoFrame(
37 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer,
Guo-wei Shieh64c1e8c2015-04-01 15:33:06 -070038 int64_t time_stamp_ns,
39 webrtc::VideoRotation rotation)
nisseb17712f2016-04-14 02:29:29 -070040 : WebRtcVideoFrame(buffer,
41 rotation,
42 time_stamp_ns / rtc::kNumNanosecsPerMicrosec) {}
Guo-wei Shieh64c1e8c2015-04-01 15:33:06 -070043
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044WebRtcVideoFrame::~WebRtcVideoFrame() {}
45
Peter Boström0c4e06b2015-10-07 12:23:21 +020046bool WebRtcVideoFrame::Init(uint32_t format,
guoweis@webrtc.org6c930c72015-02-09 01:28:12 +000047 int w,
48 int h,
49 int dw,
50 int dh,
Peter Boström0c4e06b2015-10-07 12:23:21 +020051 uint8_t* sample,
guoweis@webrtc.org6c930c72015-02-09 01:28:12 +000052 size_t sample_size,
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000053 int64_t time_stamp_ns,
guoweis@webrtc.org6c930c72015-02-09 01:28:12 +000054 webrtc::VideoRotation rotation) {
nisse8b1e4312016-01-18 01:46:27 -080055 return Reset(format, w, h, dw, dh, sample, sample_size,
nisseb17712f2016-04-14 02:29:29 -070056 time_stamp_ns / rtc::kNumNanosecsPerMicrosec, rotation,
perkj@webrtc.org1d828132015-03-03 06:44:06 +000057 true /*apply_rotation*/);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058}
59
perkj@webrtc.org1d828132015-03-03 06:44:06 +000060bool WebRtcVideoFrame::Init(const CapturedFrame* frame, int dw, int dh,
61 bool apply_rotation) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062 return Reset(frame->fourcc, frame->width, frame->height, dw, dh,
Peter Boström0c4e06b2015-10-07 12:23:21 +020063 static_cast<uint8_t*>(frame->data), frame->data_size,
nisseb17712f2016-04-14 02:29:29 -070064 frame->time_stamp / rtc::kNumNanosecsPerMicrosec,
perkj7755e202015-11-19 12:02:21 -080065 frame->rotation, apply_rotation);
magjedb09b6602015-10-01 03:02:44 -070066}
67
nisse8b1e4312016-01-18 01:46:27 -080068bool WebRtcVideoFrame::InitToBlack(int w, int h,
69 int64_t time_stamp_ns) {
70 InitToEmptyBuffer(w, h, time_stamp_ns);
thorcarpenter@google.com88d14f42014-11-22 01:04:26 +000071 return SetToBlack();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072}
73
nisse71a0c2f2016-04-04 00:57:29 -070074int WebRtcVideoFrame::width() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000075 return video_frame_buffer_ ? video_frame_buffer_->width() : 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076}
77
nisse71a0c2f2016-04-04 00:57:29 -070078int WebRtcVideoFrame::height() const {
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000079 return video_frame_buffer_ ? video_frame_buffer_->height() : 0;
80}
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081
tommi@webrtc.org1f944072015-03-04 17:33:55 +000082bool WebRtcVideoFrame::IsExclusive() const {
Niels Möller47fe34c2016-04-18 13:02:59 +020083 return video_frame_buffer_->IsMutable();
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000084}
85
86void* WebRtcVideoFrame::GetNativeHandle() const {
87 return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr;
88}
89
nisse05654512016-04-29 02:56:00 -070090const rtc::scoped_refptr<webrtc::VideoFrameBuffer>&
nissef3868762016-04-13 03:29:16 -070091WebRtcVideoFrame::video_frame_buffer() const {
magjed@webrtc.orgafdd5dd2015-03-12 13:11:25 +000092 return video_frame_buffer_;
93}
94
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +000095VideoFrame* WebRtcVideoFrame::Copy() const {
nisseb17712f2016-04-14 02:29:29 -070096 return new WebRtcVideoFrame(video_frame_buffer_, rotation_, timestamp_us_);
magjed@webrtc.org50b22952015-03-02 10:03:47 +000097}
98
Peter Boström0c4e06b2015-10-07 12:23:21 +020099size_t WebRtcVideoFrame::ConvertToRgbBuffer(uint32_t to_fourcc,
100 uint8_t* buffer,
101 size_t size,
102 int stride_rgb) const {
henrikg91d6ede2015-09-17 00:24:34 -0700103 RTC_CHECK(video_frame_buffer_);
104 RTC_CHECK(video_frame_buffer_->native_handle() == nullptr);
magjed@webrtc.orgbdcf38c2014-11-21 10:53:00 +0000105 return VideoFrame::ConvertToRgbBuffer(to_fourcc, buffer, size, stride_rgb);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106}
107
Peter Boström0c4e06b2015-10-07 12:23:21 +0200108bool WebRtcVideoFrame::Reset(uint32_t format,
guoweis@webrtc.org6c930c72015-02-09 01:28:12 +0000109 int w,
110 int h,
111 int dw,
112 int dh,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200113 uint8_t* sample,
guoweis@webrtc.org6c930c72015-02-09 01:28:12 +0000114 size_t sample_size,
nisseb17712f2016-04-14 02:29:29 -0700115 int64_t timestamp_us,
perkj@webrtc.org1d828132015-03-03 06:44:06 +0000116 webrtc::VideoRotation rotation,
117 bool apply_rotation) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118 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.org28e20752013-07-10 00:45:36 +0000124 // Set up a new buffer.
125 // TODO(fbarchard): Support lazy allocation.
126 int new_width = dw;
127 int new_height = dh;
perkj@webrtc.org1d828132015-03-03 06:44:06 +0000128 // If rotated swap width, height.
129 if (apply_rotation && (rotation == 90 || rotation == 270)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 new_width = dh;
131 new_height = dw;
132 }
133
nisseb17712f2016-04-14 02:29:29 -0700134 InitToEmptyBuffer(new_width, new_height);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000135 rotation_ = apply_rotation ? webrtc::kVideoRotation_0 : rotation;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
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.org28e20752013-07-10 00:45:36 +0000143 int r = libyuv::ConvertToI420(
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000144 sample, sample_size,
nisse05654512016-04-29 02:56:00 -0700145 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.org2386d6d2015-03-05 14:03:08 +0000151 horiz_crop, vert_crop,
152 w, h,
153 dw, idh,
perkj@webrtc.org1d828132015-03-03 06:44:06 +0000154 static_cast<libyuv::RotationMode>(
155 apply_rotation ? rotation : webrtc::kVideoRotation_0),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156 format);
157 if (r) {
158 LOG(LS_ERROR) << "Error parsing format: " << GetFourccName(format)
159 << " return code : " << r;
160 return false;
161 }
nisseb17712f2016-04-14 02:29:29 -0700162 timestamp_us_ = timestamp_us;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163 return true;
164}
165
nisseb17712f2016-04-14 02:29:29 -0700166VideoFrame* WebRtcVideoFrame::CreateEmptyFrame(int w,
167 int h,
168 int64_t timestamp_us) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000169 WebRtcVideoFrame* frame = new WebRtcVideoFrame();
nisseb17712f2016-04-14 02:29:29 -0700170 frame->InitToEmptyBuffer(w, h, rtc::kNumNanosecsPerMicrosec * timestamp_us);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171 return frame;
172}
173
nisseb17712f2016-04-14 02:29:29 -0700174void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h) {
175 video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h);
176 rotation_ = webrtc::kVideoRotation_0;
177}
178
nisse8b1e4312016-01-18 01:46:27 -0800179void WebRtcVideoFrame::InitToEmptyBuffer(int w, int h,
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000180 int64_t time_stamp_ns) {
181 video_frame_buffer_ = new rtc::RefCountedObject<webrtc::I420Buffer>(w, h);
nisseb17712f2016-04-14 02:29:29 -0700182 SetTimeStamp(time_stamp_ns);
magjed@webrtc.org2386d6d2015-03-05 14:03:08 +0000183 rotation_ = webrtc::kVideoRotation_0;
magjed@webrtc.orge575e9c2014-12-14 11:09:23 +0000184}
185
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000186const VideoFrame* WebRtcVideoFrame::GetCopyWithRotationApplied() const {
187 // If the frame is not rotated, the caller should reuse this frame instead of
188 // making a redundant copy.
nissef3868762016-04-13 03:29:16 -0700189 if (rotation() == webrtc::kVideoRotation_0) {
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000190 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.
henrikg91d6ede2015-09-17 00:24:34 -0700196 RTC_DCHECK(!GetNativeHandle());
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000197
198 if (rotated_frame_) {
199 return rotated_frame_.get();
200 }
201
nisse71a0c2f2016-04-04 00:57:29 -0700202 int orig_width = width();
203 int orig_height = height();
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000204
nisse71a0c2f2016-04-04 00:57:29 -0700205 int rotated_width = orig_width;
206 int rotated_height = orig_height;
nissef3868762016-04-13 03:29:16 -0700207 if (rotation() == webrtc::kVideoRotation_90 ||
208 rotation() == webrtc::kVideoRotation_270) {
nisse71a0c2f2016-04-04 00:57:29 -0700209 rotated_width = orig_height;
210 rotated_height = orig_width;
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000211 }
212
nisseb17712f2016-04-14 02:29:29 -0700213 rotated_frame_.reset(
214 CreateEmptyFrame(rotated_width, rotated_height, timestamp_us_));
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000215
216 // TODO(guoweis): Add a function in webrtc_libyuv.cc to convert from
217 // VideoRotation to libyuv::RotationMode.
218 int ret = libyuv::I420Rotate(
nisse05654512016-04-29 02:56:00 -0700219 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(),
nisse71a0c2f2016-04-04 00:57:29 -0700228 orig_width, orig_height,
nissef3868762016-04-13 03:29:16 -0700229 static_cast<libyuv::RotationMode>(rotation()));
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000230 if (ret == 0) {
231 return rotated_frame_.get();
232 }
233 return nullptr;
234}
235
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236} // namespace cricket