blob: bcb9478e17049815e1bf3595445b1b18d30b5745 [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äki44bd29a2019-08-27 15:09:15 +020022 private static final int RELEASE_TIMEOUT_MS = 10000;
23
Magnus Jedvert169e0422018-09-10 09:42:28 +020024 // This is the full resolution the texture has in memory after applying the transformation matrix
25 // that might include cropping. This resolution is useful to know when sampling the texture to
26 // avoid downscaling artifacts.
27 private final int unscaledWidth;
28 private final int unscaledHeight;
29 // This is the resolution that has been applied after cropAndScale().
sakal836f60c2017-07-28 07:12:23 -070030 private final int width;
31 private final int height;
32 private final Type type;
33 private final int id;
34 private final Matrix transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020035 private final Handler toI420Handler;
36 private final YuvConverter yuvConverter;
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020037 private final RefCountDelegate refCountDelegate;
sakal836f60c2017-07-28 07:12:23 -070038
39 public TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
Magnus Jedvert1d270f82018-04-16 16:28:29 +020040 Handler toI420Handler, YuvConverter yuvConverter, @Nullable Runnable releaseCallback) {
Magnus Jedvert169e0422018-09-10 09:42:28 +020041 this.unscaledWidth = width;
42 this.unscaledHeight = height;
43 this.width = width;
44 this.height = height;
45 this.type = type;
46 this.id = id;
47 this.transformMatrix = transformMatrix;
48 this.toI420Handler = toI420Handler;
49 this.yuvConverter = yuvConverter;
50 this.refCountDelegate = new RefCountDelegate(releaseCallback);
51 }
52
53 private TextureBufferImpl(int unscaledWidth, int unscaledHeight, int width, int height, Type type,
54 int id, Matrix transformMatrix, Handler toI420Handler, YuvConverter yuvConverter,
55 @Nullable Runnable releaseCallback) {
56 this.unscaledWidth = unscaledWidth;
57 this.unscaledHeight = unscaledHeight;
sakal836f60c2017-07-28 07:12:23 -070058 this.width = width;
59 this.height = height;
60 this.type = type;
61 this.id = id;
62 this.transformMatrix = transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020063 this.toI420Handler = toI420Handler;
64 this.yuvConverter = yuvConverter;
Sami Kalliomäki44bd29a2019-08-27 15:09:15 +020065 this.refCountDelegate = new RefCountDelegate(releaseCallback, RELEASE_TIMEOUT_MS);
sakal836f60c2017-07-28 07:12:23 -070066 }
67
68 @Override
69 public VideoFrame.TextureBuffer.Type getType() {
70 return type;
71 }
72
73 @Override
74 public int getTextureId() {
75 return id;
76 }
77
78 @Override
79 public Matrix getTransformMatrix() {
80 return transformMatrix;
81 }
82
83 @Override
84 public int getWidth() {
85 return width;
86 }
87
88 @Override
89 public int getHeight() {
90 return height;
91 }
92
93 @Override
94 public VideoFrame.I420Buffer toI420() {
Magnus Jedvert1d270f82018-04-16 16:28:29 +020095 return ThreadUtils.invokeAtFrontUninterruptibly(
96 toI420Handler, () -> yuvConverter.convert(this));
sakal836f60c2017-07-28 07:12:23 -070097 }
98
99 @Override
100 public void retain() {
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200101 refCountDelegate.retain();
sakal836f60c2017-07-28 07:12:23 -0700102 }
103
104 @Override
105 public void release() {
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200106 refCountDelegate.release();
sakal836f60c2017-07-28 07:12:23 -0700107 }
108
109 @Override
110 public VideoFrame.Buffer cropAndScale(
111 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200112 final Matrix cropAndScaleMatrix = new Matrix();
Magnus Jedvert65070542018-06-14 12:23:01 +0200113 // In WebRTC, Y=0 is the top row, while in OpenGL Y=0 is the bottom row. This means that the Y
114 // direction is effectively reversed.
115 final int cropYFromBottom = height - (cropY + cropHeight);
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200116 cropAndScaleMatrix.preTranslate(cropX / (float) width, cropYFromBottom / (float) height);
117 cropAndScaleMatrix.preScale(cropWidth / (float) width, cropHeight / (float) height);
Sami Kalliomäki64051d42018-04-16 13:37:07 +0000118
Magnus Jedvert169e0422018-09-10 09:42:28 +0200119 return applyTransformMatrix(cropAndScaleMatrix,
120 (int) Math.round(unscaledWidth * cropWidth / (float) width),
121 (int) Math.round(unscaledHeight * cropHeight / (float) height), scaleWidth, scaleHeight);
122 }
123
124 /**
125 * Returns the width of the texture in memory. This should only be used for downscaling, and you
126 * should still respect the width from getWidth().
127 */
128 public int getUnscaledWidth() {
129 return unscaledWidth;
130 }
131
132 /**
133 * Returns the height of the texture in memory. This should only be used for downscaling, and you
134 * should still respect the height from getHeight().
135 */
136 public int getUnscaledHeight() {
137 return unscaledHeight;
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200138 }
139
Åsa Perssonf2889bb2019-02-25 16:20:01 +0100140 public Handler getToI420Handler() {
141 return toI420Handler;
142 }
143
144 public YuvConverter getYuvConverter() {
145 return yuvConverter;
146 }
147
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200148 /**
149 * Create a new TextureBufferImpl with an applied transform matrix and a new size. The
150 * existing buffer is unchanged. The given transform matrix is applied first when texture
151 * coordinates are still in the unmodified [0, 1] range.
152 */
153 public TextureBufferImpl applyTransformMatrix(
154 Matrix transformMatrix, int newWidth, int newHeight) {
Magnus Jedvert169e0422018-09-10 09:42:28 +0200155 return applyTransformMatrix(transformMatrix, /* unscaledWidth= */ newWidth,
156 /* unscaledHeight= */ newHeight, /* scaledWidth= */ newWidth,
157 /* scaledHeight= */ newHeight);
158 }
159
160 private TextureBufferImpl applyTransformMatrix(Matrix transformMatrix, int unscaledWidth,
161 int unscaledHeight, int scaledWidth, int scaledHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200162 final Matrix newMatrix = new Matrix(this.transformMatrix);
163 newMatrix.preConcat(transformMatrix);
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200164 retain();
Magnus Jedvert169e0422018-09-10 09:42:28 +0200165 return new TextureBufferImpl(unscaledWidth, unscaledHeight, scaledWidth, scaledHeight, type, id,
166 newMatrix, toI420Handler, yuvConverter, this ::release);
sakal836f60c2017-07-28 07:12:23 -0700167 }
168}