blob: a24f2847904935503a7baebfd68cb69cdbbe0134 [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 {
Magnus Jedvert169e0422018-09-10 09:42:28 +020022 // This is the full resolution the texture has in memory after applying the transformation matrix
23 // that might include cropping. This resolution is useful to know when sampling the texture to
24 // avoid downscaling artifacts.
25 private final int unscaledWidth;
26 private final int unscaledHeight;
27 // This is the resolution that has been applied after cropAndScale().
sakal836f60c2017-07-28 07:12:23 -070028 private final int width;
29 private final int height;
30 private final Type type;
31 private final int id;
32 private final Matrix transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020033 private final Handler toI420Handler;
34 private final YuvConverter yuvConverter;
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020035 private final RefCountDelegate refCountDelegate;
sakal836f60c2017-07-28 07:12:23 -070036
37 public TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
Magnus Jedvert1d270f82018-04-16 16:28:29 +020038 Handler toI420Handler, YuvConverter yuvConverter, @Nullable Runnable releaseCallback) {
Magnus Jedvert169e0422018-09-10 09:42:28 +020039 this.unscaledWidth = width;
40 this.unscaledHeight = height;
41 this.width = width;
42 this.height = height;
43 this.type = type;
44 this.id = id;
45 this.transformMatrix = transformMatrix;
46 this.toI420Handler = toI420Handler;
47 this.yuvConverter = yuvConverter;
48 this.refCountDelegate = new RefCountDelegate(releaseCallback);
49 }
50
51 private TextureBufferImpl(int unscaledWidth, int unscaledHeight, int width, int height, Type type,
52 int id, Matrix transformMatrix, Handler toI420Handler, YuvConverter yuvConverter,
53 @Nullable Runnable releaseCallback) {
54 this.unscaledWidth = unscaledWidth;
55 this.unscaledHeight = unscaledHeight;
sakal836f60c2017-07-28 07:12:23 -070056 this.width = width;
57 this.height = height;
58 this.type = type;
59 this.id = id;
60 this.transformMatrix = transformMatrix;
Magnus Jedvert1d270f82018-04-16 16:28:29 +020061 this.toI420Handler = toI420Handler;
62 this.yuvConverter = yuvConverter;
Sami Kalliomäkifdd23402019-08-28 12:01:00 +000063 this.refCountDelegate = new RefCountDelegate(releaseCallback);
sakal836f60c2017-07-28 07:12:23 -070064 }
65
66 @Override
67 public VideoFrame.TextureBuffer.Type getType() {
68 return type;
69 }
70
71 @Override
72 public int getTextureId() {
73 return id;
74 }
75
76 @Override
77 public Matrix getTransformMatrix() {
78 return transformMatrix;
79 }
80
81 @Override
82 public int getWidth() {
83 return width;
84 }
85
86 @Override
87 public int getHeight() {
88 return height;
89 }
90
91 @Override
92 public VideoFrame.I420Buffer toI420() {
Magnus Jedvert1d270f82018-04-16 16:28:29 +020093 return ThreadUtils.invokeAtFrontUninterruptibly(
94 toI420Handler, () -> yuvConverter.convert(this));
sakal836f60c2017-07-28 07:12:23 -070095 }
96
97 @Override
98 public void retain() {
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020099 refCountDelegate.retain();
sakal836f60c2017-07-28 07:12:23 -0700100 }
101
102 @Override
103 public void release() {
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200104 refCountDelegate.release();
sakal836f60c2017-07-28 07:12:23 -0700105 }
106
107 @Override
108 public VideoFrame.Buffer cropAndScale(
109 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200110 final Matrix cropAndScaleMatrix = new Matrix();
Magnus Jedvert65070542018-06-14 12:23:01 +0200111 // In WebRTC, Y=0 is the top row, while in OpenGL Y=0 is the bottom row. This means that the Y
112 // direction is effectively reversed.
113 final int cropYFromBottom = height - (cropY + cropHeight);
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200114 cropAndScaleMatrix.preTranslate(cropX / (float) width, cropYFromBottom / (float) height);
115 cropAndScaleMatrix.preScale(cropWidth / (float) width, cropHeight / (float) height);
Sami Kalliomäki64051d42018-04-16 13:37:07 +0000116
Magnus Jedvert169e0422018-09-10 09:42:28 +0200117 return applyTransformMatrix(cropAndScaleMatrix,
118 (int) Math.round(unscaledWidth * cropWidth / (float) width),
119 (int) Math.round(unscaledHeight * cropHeight / (float) height), scaleWidth, scaleHeight);
120 }
121
122 /**
123 * Returns the width of the texture in memory. This should only be used for downscaling, and you
124 * should still respect the width from getWidth().
125 */
126 public int getUnscaledWidth() {
127 return unscaledWidth;
128 }
129
130 /**
131 * Returns the height of the texture in memory. This should only be used for downscaling, and you
132 * should still respect the height from getHeight().
133 */
134 public int getUnscaledHeight() {
135 return unscaledHeight;
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200136 }
137
Åsa Perssonf2889bb2019-02-25 16:20:01 +0100138 public Handler getToI420Handler() {
139 return toI420Handler;
140 }
141
142 public YuvConverter getYuvConverter() {
143 return yuvConverter;
144 }
145
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200146 /**
147 * Create a new TextureBufferImpl with an applied transform matrix and a new size. The
148 * existing buffer is unchanged. The given transform matrix is applied first when texture
149 * coordinates are still in the unmodified [0, 1] range.
150 */
151 public TextureBufferImpl applyTransformMatrix(
152 Matrix transformMatrix, int newWidth, int newHeight) {
Magnus Jedvert169e0422018-09-10 09:42:28 +0200153 return applyTransformMatrix(transformMatrix, /* unscaledWidth= */ newWidth,
154 /* unscaledHeight= */ newHeight, /* scaledWidth= */ newWidth,
155 /* scaledHeight= */ newHeight);
156 }
157
158 private TextureBufferImpl applyTransformMatrix(Matrix transformMatrix, int unscaledWidth,
159 int unscaledHeight, int scaledWidth, int scaledHeight) {
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200160 final Matrix newMatrix = new Matrix(this.transformMatrix);
161 newMatrix.preConcat(transformMatrix);
Magnus Jedvert1d270f82018-04-16 16:28:29 +0200162 retain();
Magnus Jedvert169e0422018-09-10 09:42:28 +0200163 return new TextureBufferImpl(unscaledWidth, unscaledHeight, scaledWidth, scaledHeight, type, id,
164 newMatrix, toI420Handler, yuvConverter, this ::release);
sakal836f60c2017-07-28 07:12:23 -0700165 }
166}