blob: 710a06d3dcb54c96ee8c08429dbc997fcbc1732c [file] [log] [blame]
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -07001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.
9 */
10
11#include "webrtc/video_frame.h"
12
13#include <string.h>
14
15#include <algorithm> // swap
16
17#include "webrtc/base/bind.h"
18#include "webrtc/base/checks.h"
19
20namespace webrtc {
21
jackychen67e94fb2016-01-11 21:34:07 -080022bool EqualPlane(const uint8_t* data1,
23 const uint8_t* data2,
24 int stride,
25 int width,
26 int height) {
27 for (int y = 0; y < height; ++y) {
28 if (memcmp(data1, data2, width) != 0)
29 return false;
30 data1 += stride;
31 data2 += stride;
32 }
33 return true;
34}
35
36int ExpectedSize(int plane_stride, int image_height, PlaneType type) {
37 if (type == kYPlane) {
38 return (plane_stride * image_height);
39 } else {
40 int half_height = (image_height + 1) / 2;
41 return (plane_stride * half_height);
42 }
43}
44
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070045VideoFrame::VideoFrame() {
46 // Intentionally using Reset instead of initializer list so that any missed
47 // fields in Reset will be caught by memory checkers.
48 Reset();
49}
50
51VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
52 uint32_t timestamp,
53 int64_t render_time_ms,
54 VideoRotation rotation)
55 : video_frame_buffer_(buffer),
56 timestamp_(timestamp),
57 ntp_time_ms_(0),
58 render_time_ms_(render_time_ms),
59 rotation_(rotation) {
60}
61
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070062int VideoFrame::CreateEmptyFrame(int width,
63 int height,
64 int stride_y,
65 int stride_u,
66 int stride_v) {
67 const int half_width = (width + 1) / 2;
henrikg91d6ede2015-09-17 00:24:34 -070068 RTC_DCHECK_GT(width, 0);
69 RTC_DCHECK_GT(height, 0);
70 RTC_DCHECK_GE(stride_y, width);
71 RTC_DCHECK_GE(stride_u, half_width);
72 RTC_DCHECK_GE(stride_v, half_width);
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070073
74 // Creating empty frame - reset all values.
75 timestamp_ = 0;
76 ntp_time_ms_ = 0;
77 render_time_ms_ = 0;
78 rotation_ = kVideoRotation_0;
79
80 // Check if it's safe to reuse allocation.
81 if (video_frame_buffer_ && video_frame_buffer_->HasOneRef() &&
82 !video_frame_buffer_->native_handle() &&
83 width == video_frame_buffer_->width() &&
84 height == video_frame_buffer_->height() && stride_y == stride(kYPlane) &&
85 stride_u == stride(kUPlane) && stride_v == stride(kVPlane)) {
86 return 0;
87 }
88
89 // Need to allocate new buffer.
90 video_frame_buffer_ = new rtc::RefCountedObject<I420Buffer>(
91 width, height, stride_y, stride_u, stride_v);
92 return 0;
93}
94
95int VideoFrame::CreateFrame(const uint8_t* buffer_y,
96 const uint8_t* buffer_u,
97 const uint8_t* buffer_v,
98 int width,
99 int height,
100 int stride_y,
101 int stride_u,
102 int stride_v) {
103 return CreateFrame(buffer_y, buffer_u, buffer_v, width, height, stride_y,
104 stride_u, stride_v, kVideoRotation_0);
105}
106
107int VideoFrame::CreateFrame(const uint8_t* buffer_y,
108 const uint8_t* buffer_u,
109 const uint8_t* buffer_v,
110 int width,
111 int height,
112 int stride_y,
113 int stride_u,
114 int stride_v,
115 VideoRotation rotation) {
116 const int half_height = (height + 1) / 2;
117 const int expected_size_y = height * stride_y;
118 const int expected_size_u = half_height * stride_u;
119 const int expected_size_v = half_height * stride_v;
120 CreateEmptyFrame(width, height, stride_y, stride_u, stride_v);
121 memcpy(buffer(kYPlane), buffer_y, expected_size_y);
122 memcpy(buffer(kUPlane), buffer_u, expected_size_u);
123 memcpy(buffer(kVPlane), buffer_v, expected_size_v);
124 rotation_ = rotation;
125 return 0;
126}
127
128int VideoFrame::CreateFrame(const uint8_t* buffer,
129 int width,
130 int height,
131 VideoRotation rotation) {
132 const int stride_y = width;
133 const int stride_uv = (width + 1) / 2;
134
135 const uint8_t* buffer_y = buffer;
136 const uint8_t* buffer_u = buffer_y + stride_y * height;
137 const uint8_t* buffer_v = buffer_u + stride_uv * ((height + 1) / 2);
138 return CreateFrame(buffer_y, buffer_u, buffer_v, width, height, stride_y,
139 stride_uv, stride_uv, rotation);
140}
141
142int VideoFrame::CopyFrame(const VideoFrame& videoFrame) {
143 if (videoFrame.IsZeroSize()) {
144 video_frame_buffer_ = nullptr;
145 } else if (videoFrame.native_handle()) {
146 video_frame_buffer_ = videoFrame.video_frame_buffer();
147 } else {
148 CreateFrame(videoFrame.buffer(kYPlane), videoFrame.buffer(kUPlane),
149 videoFrame.buffer(kVPlane), videoFrame.width(),
150 videoFrame.height(), videoFrame.stride(kYPlane),
151 videoFrame.stride(kUPlane), videoFrame.stride(kVPlane));
152 }
153
154 timestamp_ = videoFrame.timestamp_;
155 ntp_time_ms_ = videoFrame.ntp_time_ms_;
156 render_time_ms_ = videoFrame.render_time_ms_;
157 rotation_ = videoFrame.rotation_;
158 return 0;
159}
160
161void VideoFrame::ShallowCopy(const VideoFrame& videoFrame) {
162 video_frame_buffer_ = videoFrame.video_frame_buffer();
163 timestamp_ = videoFrame.timestamp_;
164 ntp_time_ms_ = videoFrame.ntp_time_ms_;
165 render_time_ms_ = videoFrame.render_time_ms_;
166 rotation_ = videoFrame.rotation_;
167}
168
169void VideoFrame::Reset() {
170 video_frame_buffer_ = nullptr;
171 timestamp_ = 0;
172 ntp_time_ms_ = 0;
173 render_time_ms_ = 0;
174 rotation_ = kVideoRotation_0;
175}
176
177uint8_t* VideoFrame::buffer(PlaneType type) {
Magnus Jedvert3318f982015-08-26 16:06:21 +0200178 return video_frame_buffer_ ? video_frame_buffer_->MutableData(type)
179 : nullptr;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700180}
181
182const uint8_t* VideoFrame::buffer(PlaneType type) const {
Magnus Jedvert3318f982015-08-26 16:06:21 +0200183 return video_frame_buffer_ ? video_frame_buffer_->data(type) : nullptr;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700184}
185
186int VideoFrame::allocated_size(PlaneType type) const {
187 const int plane_height = (type == kYPlane) ? height() : (height() + 1) / 2;
188 return plane_height * stride(type);
189}
190
191int VideoFrame::stride(PlaneType type) const {
192 return video_frame_buffer_ ? video_frame_buffer_->stride(type) : 0;
193}
194
195int VideoFrame::width() const {
196 return video_frame_buffer_ ? video_frame_buffer_->width() : 0;
197}
198
199int VideoFrame::height() const {
200 return video_frame_buffer_ ? video_frame_buffer_->height() : 0;
201}
202
203bool VideoFrame::IsZeroSize() const {
204 return !video_frame_buffer_;
205}
206
207void* VideoFrame::native_handle() const {
208 return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr;
209}
210
211rtc::scoped_refptr<VideoFrameBuffer> VideoFrame::video_frame_buffer() const {
212 return video_frame_buffer_;
213}
214
215void VideoFrame::set_video_frame_buffer(
216 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer) {
217 video_frame_buffer_ = buffer;
218}
219
Peter Boströmeb66e802015-06-05 11:08:03 +0200220VideoFrame VideoFrame::ConvertNativeToI420Frame() const {
henrikg91d6ede2015-09-17 00:24:34 -0700221 RTC_DCHECK(native_handle());
Peter Boströmeb66e802015-06-05 11:08:03 +0200222 VideoFrame frame;
223 frame.ShallowCopy(*this);
224 frame.set_video_frame_buffer(video_frame_buffer_->NativeToI420Buffer());
225 return frame;
226}
227
jackychen67e94fb2016-01-11 21:34:07 -0800228bool VideoFrame::EqualsFrame(const VideoFrame& frame) const {
229 if ((this->width() != frame.width()) || (this->height() != frame.height()) ||
230 (this->stride(kYPlane) != frame.stride(kYPlane)) ||
231 (this->stride(kUPlane) != frame.stride(kUPlane)) ||
232 (this->stride(kVPlane) != frame.stride(kVPlane)) ||
233 (this->timestamp() != frame.timestamp()) ||
234 (this->ntp_time_ms() != frame.ntp_time_ms()) ||
235 (this->render_time_ms() != frame.render_time_ms())) {
236 return false;
237 }
238 const int half_width = (this->width() + 1) / 2;
239 const int half_height = (this->height() + 1) / 2;
240 return EqualPlane(this->buffer(kYPlane), frame.buffer(kYPlane),
241 this->stride(kYPlane), this->width(), this->height()) &&
242 EqualPlane(this->buffer(kUPlane), frame.buffer(kUPlane),
243 this->stride(kUPlane), half_width, half_height) &&
244 EqualPlane(this->buffer(kVPlane), frame.buffer(kVPlane),
245 this->stride(kVPlane), half_width, half_height);
246}
247
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700248} // namespace webrtc