blob: 8d752162dc9d43a1dfe9409d4921302bc93ce329 [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äki9c712bb2019-10-21 17:06:02 +020042 private final 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) {
Sami Kalliomäki9c712bb2019-10-21 17:06:02 +020056 if (releaseCallback != null) {
57 releaseCallback.run();
58 }
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020059 }
60 });
61 }
62
63 TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
64 Handler toI420Handler, YuvConverter yuvConverter, RefCountMonitor refCountMonitor) {
65 this(width, height, width, height, type, id, transformMatrix, toI420Handler, yuvConverter,
66 refCountMonitor);
Magnus Jedvert169e0422018-09-10 09:42:28 +020067 }
68
69 private TextureBufferImpl(int unscaledWidth, int unscaledHeight, int width, int height, Type type,
70 int id, Matrix transformMatrix, Handler toI420Handler, YuvConverter yuvConverter,
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020071 RefCountMonitor refCountMonitor) {
Magnus Jedvert169e0422018-09-10 09:42:28 +020072 this.unscaledWidth = unscaledWidth;
73 this.unscaledHeight = unscaledHeight;
sakal836f60c2017-07-28 07:12:23 -070074 this.width = width;
75 this.height = height;
76 this.type = type;
77 this.id = id;
78 this.transformMatrix = transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020079 this.toI420Handler = toI420Handler;
80 this.yuvConverter = yuvConverter;
Sami Kalliomäki066b42f2019-08-30 11:20:42 +020081 this.refCountDelegate = new RefCountDelegate(() -> refCountMonitor.onDestroy(this));
82 this.refCountMonitor = refCountMonitor;
sakal836f60c2017-07-28 07:12:23 -070083 }
84
85 @Override
86 public VideoFrame.TextureBuffer.Type getType() {
87 return type;
88 }
89
90 @Override
91 public int getTextureId() {
92 return id;
93 }
94
95 @Override
96 public Matrix getTransformMatrix() {
97 return transformMatrix;
98 }
99
100 @Override
101 public int getWidth() {
102 return width;
103 }
104
105 @Override
106 public int getHeight() {
107 return height;
108 }
109
110 @Override
111 public VideoFrame.I420Buffer toI420() {
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200112 return ThreadUtils.invokeAtFrontUninterruptibly(
113 toI420Handler, () -> yuvConverter.convert(this));
sakal836f60c2017-07-28 07:12:23 -0700114 }
115
116 @Override
117 public void retain() {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200118 refCountMonitor.onRetain(this);
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200119 refCountDelegate.retain();
sakal836f60c2017-07-28 07:12:23 -0700120 }
121
122 @Override
123 public void release() {
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200124 refCountMonitor.onRelease(this);
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200125 refCountDelegate.release();
sakal836f60c2017-07-28 07:12:23 -0700126 }
127
128 @Override
129 public VideoFrame.Buffer cropAndScale(
130 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200131 final Matrix cropAndScaleMatrix = new Matrix();
Magnus Jedvert65070542018-06-14 12:23:01 +0200132 // In WebRTC, Y=0 is the top row, while in OpenGL Y=0 is the bottom row. This means that the Y
133 // direction is effectively reversed.
134 final int cropYFromBottom = height - (cropY + cropHeight);
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200135 cropAndScaleMatrix.preTranslate(cropX / (float) width, cropYFromBottom / (float) height);
136 cropAndScaleMatrix.preScale(cropWidth / (float) width, cropHeight / (float) height);
Sami Kalliomäki64051d42018-04-16 13:37:07 +0000137
Magnus Jedvert169e0422018-09-10 09:42:28 +0200138 return applyTransformMatrix(cropAndScaleMatrix,
139 (int) Math.round(unscaledWidth * cropWidth / (float) width),
140 (int) Math.round(unscaledHeight * cropHeight / (float) height), scaleWidth, scaleHeight);
141 }
142
143 /**
144 * Returns the width of the texture in memory. This should only be used for downscaling, and you
145 * should still respect the width from getWidth().
146 */
147 public int getUnscaledWidth() {
148 return unscaledWidth;
149 }
150
151 /**
152 * Returns the height of the texture in memory. This should only be used for downscaling, and you
153 * should still respect the height from getHeight().
154 */
155 public int getUnscaledHeight() {
156 return unscaledHeight;
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200157 }
158
Åsa Perssonf2889bb2019-02-25 16:20:01 +0100159 public Handler getToI420Handler() {
160 return toI420Handler;
161 }
162
163 public YuvConverter getYuvConverter() {
164 return yuvConverter;
165 }
166
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200167 /**
168 * Create a new TextureBufferImpl with an applied transform matrix and a new size. The
169 * existing buffer is unchanged. The given transform matrix is applied first when texture
170 * coordinates are still in the unmodified [0, 1] range.
171 */
172 public TextureBufferImpl applyTransformMatrix(
173 Matrix transformMatrix, int newWidth, int newHeight) {
Magnus Jedvert169e0422018-09-10 09:42:28 +0200174 return applyTransformMatrix(transformMatrix, /* unscaledWidth= */ newWidth,
175 /* unscaledHeight= */ newHeight, /* scaledWidth= */ newWidth,
176 /* scaledHeight= */ newHeight);
177 }
178
179 private TextureBufferImpl applyTransformMatrix(Matrix transformMatrix, int unscaledWidth,
180 int unscaledHeight, int scaledWidth, int scaledHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200181 final Matrix newMatrix = new Matrix(this.transformMatrix);
182 newMatrix.preConcat(transformMatrix);
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200183 retain();
Magnus Jedvert169e0422018-09-10 09:42:28 +0200184 return new TextureBufferImpl(unscaledWidth, unscaledHeight, scaledWidth, scaledHeight, type, id,
Sami Kalliomäki066b42f2019-08-30 11:20:42 +0200185 newMatrix, toI420Handler, yuvConverter, new RefCountMonitor() {
186 @Override
187 public void onRetain(TextureBufferImpl textureBuffer) {
188 refCountMonitor.onRetain(TextureBufferImpl.this);
189 }
190
191 @Override
192 public void onRelease(TextureBufferImpl textureBuffer) {
193 refCountMonitor.onRelease(TextureBufferImpl.this);
194 }
195
196 @Override
197 public void onDestroy(TextureBufferImpl textureBuffer) {
198 release();
199 }
200 });
sakal836f60c2017-07-28 07:12:23 -0700201 }
202}