blob: 13ed63bf183572edc1ba894f7bc76fe317a6818a [file] [log] [blame]
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -07001/*
2 * Copyright 2017 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
11package org.webrtc;
12
13import java.nio.ByteBuffer;
14import org.webrtc.VideoFrame.I420Buffer;
15
Sami Kalliomäki48b3c022017-10-04 17:01:00 +020016/** Implementation of VideoFrame.I420Buffer backed by Java direct byte buffers. */
17public class JavaI420Buffer implements VideoFrame.I420Buffer {
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -070018 private final int width;
19 private final int height;
sakal836f60c2017-07-28 07:12:23 -070020 private final ByteBuffer dataY;
21 private final ByteBuffer dataU;
22 private final ByteBuffer dataV;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070023 private final int strideY;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070024 private final int strideU;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070025 private final int strideV;
sakal836f60c2017-07-28 07:12:23 -070026 private final Runnable releaseCallback;
sakal2fe9dfa2017-08-21 08:02:58 -070027 private final Object refCountLock = new Object();
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -070028
Bjorn Mellem8fb23612017-07-18 11:33:39 -070029 private int refCount;
30
Sami Kalliomäki48b3c022017-10-04 17:01:00 +020031 private JavaI420Buffer(int width, int height, ByteBuffer dataY, int strideY, ByteBuffer dataU,
sakal836f60c2017-07-28 07:12:23 -070032 int strideU, ByteBuffer dataV, int strideV, Runnable releaseCallback) {
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -070033 this.width = width;
34 this.height = height;
sakal836f60c2017-07-28 07:12:23 -070035 this.dataY = dataY;
36 this.dataU = dataU;
37 this.dataV = dataV;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070038 this.strideY = strideY;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070039 this.strideU = strideU;
Bjorn Mellem8fb23612017-07-18 11:33:39 -070040 this.strideV = strideV;
41 this.releaseCallback = releaseCallback;
42
43 this.refCount = 1;
44 }
45
Sami Kalliomäki48b3c022017-10-04 17:01:00 +020046 /** Wraps existing ByteBuffers into JavaI420Buffer object without copying the contents. */
47 public static JavaI420Buffer wrap(int width, int height, ByteBuffer dataY, int strideY,
48 ByteBuffer dataU, int strideU, ByteBuffer dataV, int strideV, Runnable releaseCallback) {
49 if (dataY == null || dataU == null || dataV == null) {
50 throw new IllegalArgumentException("Data buffers cannot be null.");
51 }
52 if (!dataY.isDirect() || !dataU.isDirect() || !dataV.isDirect()) {
53 throw new IllegalArgumentException("Data buffers must be direct byte buffers.");
54 }
55
56 // Slice the buffers to prevent external modifications to the position / limit of the buffer.
57 // Note that this doesn't protect the contents of the buffers from modifications.
58 dataY = dataY.slice();
59 dataU = dataU.slice();
60 dataV = dataV.slice();
61
62 final int chromaHeight = (height + 1) / 2;
63 final int minCapacityY = strideY * height;
64 final int minCapacityU = strideU * chromaHeight;
65 final int minCapacityV = strideV * chromaHeight;
66 if (dataY.capacity() < minCapacityY) {
67 throw new IllegalArgumentException("Y-buffer must be at least " + minCapacityY + " bytes.");
68 }
69 if (dataU.capacity() < minCapacityU) {
70 throw new IllegalArgumentException("U-buffer must be at least " + minCapacityU + " bytes.");
71 }
72 if (dataV.capacity() < minCapacityV) {
73 throw new IllegalArgumentException("V-buffer must be at least " + minCapacityV + " bytes.");
74 }
75
76 return new JavaI420Buffer(
77 width, height, dataY, strideY, dataU, strideU, dataV, strideV, releaseCallback);
78 }
79
Bjorn Mellem8fb23612017-07-18 11:33:39 -070080 /** Allocates an empty I420Buffer suitable for an image of the given dimensions. */
Sami Kalliomäki48b3c022017-10-04 17:01:00 +020081 public static JavaI420Buffer allocate(int width, int height) {
Bjorn Mellem8fb23612017-07-18 11:33:39 -070082 int chromaHeight = (height + 1) / 2;
83 int strideUV = (width + 1) / 2;
84 int yPos = 0;
85 int uPos = yPos + width * height;
86 int vPos = uPos + strideUV * chromaHeight;
sakal836f60c2017-07-28 07:12:23 -070087
Bjorn Mellem8fb23612017-07-18 11:33:39 -070088 ByteBuffer buffer = ByteBuffer.allocateDirect(width * height + 2 * strideUV * chromaHeight);
sakal836f60c2017-07-28 07:12:23 -070089
90 buffer.position(yPos);
91 buffer.limit(uPos);
92 ByteBuffer dataY = buffer.slice();
93
94 buffer.position(uPos);
95 buffer.limit(vPos);
96 ByteBuffer dataU = buffer.slice();
97
98 buffer.position(vPos);
99 buffer.limit(vPos + strideUV * chromaHeight);
100 ByteBuffer dataV = buffer.slice();
101
Sami Kalliomäki48b3c022017-10-04 17:01:00 +0200102 return new JavaI420Buffer(
103 width, height, dataY, width, dataU, strideUV, dataV, strideUV, null /* releaseCallback */);
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700104 }
105
106 @Override
107 public int getWidth() {
108 return width;
109 }
110
111 @Override
112 public int getHeight() {
113 return height;
114 }
115
116 @Override
117 public ByteBuffer getDataY() {
Bjorn Mellemd6293142017-09-29 11:33:52 -0700118 // Return a slice to prevent relative reads from changing the position.
119 return dataY.slice();
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700120 }
121
122 @Override
123 public ByteBuffer getDataU() {
Bjorn Mellemd6293142017-09-29 11:33:52 -0700124 // Return a slice to prevent relative reads from changing the position.
125 return dataU.slice();
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700126 }
127
128 @Override
129 public ByteBuffer getDataV() {
Bjorn Mellemd6293142017-09-29 11:33:52 -0700130 // Return a slice to prevent relative reads from changing the position.
131 return dataV.slice();
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700132 }
133
134 @Override
135 public int getStrideY() {
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700136 return strideY;
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700137 }
138
139 @Override
140 public int getStrideU() {
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700141 return strideU;
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700142 }
143
144 @Override
145 public int getStrideV() {
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700146 return strideV;
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700147 }
148
149 @Override
150 public I420Buffer toI420() {
sakal5ca60cc2017-08-09 05:25:49 -0700151 retain();
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700152 return this;
153 }
154
155 @Override
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700156 public void retain() {
sakal2fe9dfa2017-08-21 08:02:58 -0700157 synchronized (refCountLock) {
158 ++refCount;
159 }
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700160 }
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700161
162 @Override
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700163 public void release() {
sakal2fe9dfa2017-08-21 08:02:58 -0700164 synchronized (refCountLock) {
165 if (--refCount == 0 && releaseCallback != null) {
166 releaseCallback.run();
167 }
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700168 }
169 }
170
sakal836f60c2017-07-28 07:12:23 -0700171 @Override
172 public VideoFrame.Buffer cropAndScale(
173 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
174 return VideoFrame.cropAndScaleI420(
175 this, cropX, cropY, cropWidth, cropHeight, scaleWidth, scaleHeight);
Bjorn Mellem8fb23612017-07-18 11:33:39 -0700176 }
Bjorn Mellem9fbbdc22017-06-16 09:23:50 -0700177}