blob: 3d3bbabf914ddefaca322b867c717c09c7d6f6c4 [file] [log] [blame]
sakal836f60c2017-07-28 07:12:23 -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 android.graphics.Matrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020014import android.os.Handler;
Artem Titarenko69540f42018-12-10 12:30:46 +010015import android.support.annotation.Nullable;
sakal836f60c2017-07-28 07:12:23 -070016
17/**
Magnus Jedvert1d270f82018-04-16 16:28:29 +020018 * Android texture buffer that glues together the necessary information together with a generic
19 * release callback. ToI420() is implemented by providing a Handler and a YuvConverter.
sakal836f60c2017-07-28 07:12:23 -070020 */
Magnus Jedvert1d270f82018-04-16 16:28:29 +020021public class TextureBufferImpl implements VideoFrame.TextureBuffer {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020022 interface RefCountMonitor {
23 void onRetain(TextureBufferImpl textureBuffer);
24 void onRelease(TextureBufferImpl textureBuffer);
25 void onDestroy(TextureBufferImpl textureBuffer);
26 }
27
Magnus Jedvert169e0422018-09-10 09:42:28 +020028 // This is the full resolution the texture has in memory after applying the transformation matrix
29 // that might include cropping. This resolution is useful to know when sampling the texture to
30 // avoid downscaling artifacts.
31 private final int unscaledWidth;
32 private final int unscaledHeight;
33 // This is the resolution that has been applied after cropAndScale().
sakal836f60c2017-07-28 07:12:23 -070034 private final int width;
35 private final int height;
36 private final Type type;
37 private final int id;
38 private final Matrix transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020039 private final Handler toI420Handler;
40 private final YuvConverter yuvConverter;
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020041 private final RefCountDelegate refCountDelegate;
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020042 private final @Nullable RefCountMonitor refCountMonitor;
sakal836f60c2017-07-28 07:12:23 -070043
44 public TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
Magnus Jedvert1d270f82018-04-16 16:28:29 +020045 Handler toI420Handler, YuvConverter yuvConverter, @Nullable Runnable releaseCallback) {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020046 this(width, height, width, height, type, id, transformMatrix, toI420Handler, yuvConverter,
47 new RefCountMonitor() {
48 @Override
49 public void onRetain(TextureBufferImpl textureBuffer) {}
50
51 @Override
52 public void onRelease(TextureBufferImpl textureBuffer) {}
53
54 @Override
55 public void onDestroy(TextureBufferImpl textureBuffer) {
56 releaseCallback.run();
57 }
58 });
59 }
60
61 TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
62 Handler toI420Handler, YuvConverter yuvConverter, RefCountMonitor refCountMonitor) {
63 this(width, height, width, height, type, id, transformMatrix, toI420Handler, yuvConverter,
64 refCountMonitor);
Magnus Jedvert169e0422018-09-10 09:42:28 +020065 }
66
67 private TextureBufferImpl(int unscaledWidth, int unscaledHeight, int width, int height, Type type,
68 int id, Matrix transformMatrix, Handler toI420Handler, YuvConverter yuvConverter,
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020069 RefCountMonitor refCountMonitor) {
Magnus Jedvert169e0422018-09-10 09:42:28 +020070 this.unscaledWidth = unscaledWidth;
71 this.unscaledHeight = unscaledHeight;
sakal836f60c2017-07-28 07:12:23 -070072 this.width = width;
73 this.height = height;
74 this.type = type;
75 this.id = id;
76 this.transformMatrix = transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020077 this.toI420Handler = toI420Handler;
78 this.yuvConverter = yuvConverter;
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020079 this.refCountDelegate = new RefCountDelegate(() -> refCountMonitor.onDestroy(this));
80 this.refCountMonitor = refCountMonitor;
sakal836f60c2017-07-28 07:12:23 -070081 }
82
83 @Override
84 public VideoFrame.TextureBuffer.Type getType() {
85 return type;
86 }
87
88 @Override
89 public int getTextureId() {
90 return id;
91 }
92
93 @Override
94 public Matrix getTransformMatrix() {
95 return transformMatrix;
96 }
97
98 @Override
99 public int getWidth() {
100 return width;
101 }
102
103 @Override
104 public int getHeight() {
105 return height;
106 }
107
108 @Override
109 public VideoFrame.I420Buffer toI420() {
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200110 return ThreadUtils.invokeAtFrontUninterruptibly(
111 toI420Handler, () -> yuvConverter.convert(this));
sakal836f60c2017-07-28 07:12:23 -0700112 }
113
114 @Override
115 public void retain() {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200116 refCountMonitor.onRetain(this);
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200117 refCountDelegate.retain();
sakal836f60c2017-07-28 07:12:23 -0700118 }
119
120 @Override
121 public void release() {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200122 refCountMonitor.onRelease(this);
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200123 refCountDelegate.release();
sakal836f60c2017-07-28 07:12:23 -0700124 }
125
126 @Override
127 public VideoFrame.Buffer cropAndScale(
128 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200129 final Matrix cropAndScaleMatrix = new Matrix();
Magnus Jedvert65070542018-06-14 12:23:01 +0200130 // In WebRTC, Y=0 is the top row, while in OpenGL Y=0 is the bottom row. This means that the Y
131 // direction is effectively reversed.
132 final int cropYFromBottom = height - (cropY + cropHeight);
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200133 cropAndScaleMatrix.preTranslate(cropX / (float) width, cropYFromBottom / (float) height);
134 cropAndScaleMatrix.preScale(cropWidth / (float) width, cropHeight / (float) height);
Sami Kalliomäki64051d42018-04-16 13:37:07 +0000135
Magnus Jedvert169e0422018-09-10 09:42:28 +0200136 return applyTransformMatrix(cropAndScaleMatrix,
137 (int) Math.round(unscaledWidth * cropWidth / (float) width),
138 (int) Math.round(unscaledHeight * cropHeight / (float) height), scaleWidth, scaleHeight);
139 }
140
141 /**
142 * Returns the width of the texture in memory. This should only be used for downscaling, and you
143 * should still respect the width from getWidth().
144 */
145 public int getUnscaledWidth() {
146 return unscaledWidth;
147 }
148
149 /**
150 * Returns the height of the texture in memory. This should only be used for downscaling, and you
151 * should still respect the height from getHeight().
152 */
153 public int getUnscaledHeight() {
154 return unscaledHeight;
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200155 }
156
Åsa Perssonf2889bb2019-02-25 16:20:01 +0100157 public Handler getToI420Handler() {
158 return toI420Handler;
159 }
160
161 public YuvConverter getYuvConverter() {
162 return yuvConverter;
163 }
164
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200165 /**
166 * Create a new TextureBufferImpl with an applied transform matrix and a new size. The
167 * existing buffer is unchanged. The given transform matrix is applied first when texture
168 * coordinates are still in the unmodified [0, 1] range.
169 */
170 public TextureBufferImpl applyTransformMatrix(
171 Matrix transformMatrix, int newWidth, int newHeight) {
Magnus Jedvert169e0422018-09-10 09:42:28 +0200172 return applyTransformMatrix(transformMatrix, /* unscaledWidth= */ newWidth,
173 /* unscaledHeight= */ newHeight, /* scaledWidth= */ newWidth,
174 /* scaledHeight= */ newHeight);
175 }
176
177 private TextureBufferImpl applyTransformMatrix(Matrix transformMatrix, int unscaledWidth,
178 int unscaledHeight, int scaledWidth, int scaledHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200179 final Matrix newMatrix = new Matrix(this.transformMatrix);
180 newMatrix.preConcat(transformMatrix);
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200181 retain();
Magnus Jedvert169e0422018-09-10 09:42:28 +0200182 return new TextureBufferImpl(unscaledWidth, unscaledHeight, scaledWidth, scaledHeight, type, id,
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200183 newMatrix, toI420Handler, yuvConverter, new RefCountMonitor() {
184 @Override
185 public void onRetain(TextureBufferImpl textureBuffer) {
186 refCountMonitor.onRetain(TextureBufferImpl.this);
187 }
188
189 @Override
190 public void onRelease(TextureBufferImpl textureBuffer) {
191 refCountMonitor.onRelease(TextureBufferImpl.this);
192 }
193
194 @Override
195 public void onDestroy(TextureBufferImpl textureBuffer) {
196 release();
197 }
198 });
sakal836f60c2017-07-28 07:12:23 -0700199 }
200}