1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import android.graphics.Matrix;
import android.os.Handler;
import androidx.annotation.Nullable;
/**
* Android texture buffer that glues together the necessary information together with a generic
* release callback. ToI420() is implemented by providing a Handler and a YuvConverter.
*/
public class TextureBufferImpl implements VideoFrame.TextureBuffer {
interface RefCountMonitor {
void onRetain(TextureBufferImpl textureBuffer);
void onRelease(TextureBufferImpl textureBuffer);
void onDestroy(TextureBufferImpl textureBuffer);
}
// This is the full resolution the texture has in memory after applying the transformation matrix
// that might include cropping. This resolution is useful to know when sampling the texture to
// avoid downscaling artifacts.
private final int unscaledWidth;
private final int unscaledHeight;
// This is the resolution that has been applied after cropAndScale().
private final int width;
private final int height;
private final Type type;
private final int id;
private final Matrix transformMatrix;
private final Handler toI420Handler;
private final YuvConverter yuvConverter;
private final RefCountDelegate refCountDelegate;
private final RefCountMonitor refCountMonitor;
public TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
Handler toI420Handler, YuvConverter yuvConverter, @Nullable Runnable releaseCallback) {
this(width, height, width, height, type, id, transformMatrix, toI420Handler, yuvConverter,
new RefCountMonitor() {
@Override
public void onRetain(TextureBufferImpl textureBuffer) {}
@Override
public void onRelease(TextureBufferImpl textureBuffer) {}
@Override
public void onDestroy(TextureBufferImpl textureBuffer) {
if (releaseCallback != null) {
releaseCallback.run();
}
}
});
}
TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix,
Handler toI420Handler, YuvConverter yuvConverter, RefCountMonitor refCountMonitor) {
this(width, height, width, height, type, id, transformMatrix, toI420Handler, yuvConverter,
refCountMonitor);
}
private TextureBufferImpl(int unscaledWidth, int unscaledHeight, int width, int height, Type type,
int id, Matrix transformMatrix, Handler toI420Handler, YuvConverter yuvConverter,
RefCountMonitor refCountMonitor) {
this.unscaledWidth = unscaledWidth;
this.unscaledHeight = unscaledHeight;
this.width = width;
this.height = height;
this.type = type;
this.id = id;
this.transformMatrix = transformMatrix;
this.toI420Handler = toI420Handler;
this.yuvConverter = yuvConverter;
this.refCountDelegate = new RefCountDelegate(() -> refCountMonitor.onDestroy(this));
this.refCountMonitor = refCountMonitor;
}
@Override
public VideoFrame.TextureBuffer.Type getType() {
return type;
}
@Override
public int getTextureId() {
return id;
}
@Override
public Matrix getTransformMatrix() {
return transformMatrix;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public VideoFrame.I420Buffer toI420() {
return ThreadUtils.invokeAtFrontUninterruptibly(
toI420Handler, () -> yuvConverter.convert(this));
}
@Override
public void retain() {
refCountMonitor.onRetain(this);
refCountDelegate.retain();
}
@Override
public void release() {
refCountMonitor.onRelease(this);
refCountDelegate.release();
}
@Override
public VideoFrame.Buffer cropAndScale(
int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) {
final Matrix cropAndScaleMatrix = new Matrix();
// In WebRTC, Y=0 is the top row, while in OpenGL Y=0 is the bottom row. This means that the Y
// direction is effectively reversed.
final int cropYFromBottom = height - (cropY + cropHeight);
cropAndScaleMatrix.preTranslate(cropX / (float) width, cropYFromBottom / (float) height);
cropAndScaleMatrix.preScale(cropWidth / (float) width, cropHeight / (float) height);
return applyTransformMatrix(cropAndScaleMatrix,
Math.round(unscaledWidth * cropWidth / (float) width),
Math.round(unscaledHeight * cropHeight / (float) height), scaleWidth, scaleHeight);
}
@Override
public int getUnscaledWidth() {
return unscaledWidth;
}
@Override
public int getUnscaledHeight() {
return unscaledHeight;
}
public Handler getToI420Handler() {
return toI420Handler;
}
public YuvConverter getYuvConverter() {
return yuvConverter;
}
/**
* Create a new TextureBufferImpl with an applied transform matrix and a new size. The
* existing buffer is unchanged. The given transform matrix is applied first when texture
* coordinates are still in the unmodified [0, 1] range.
*/
@Override
public TextureBufferImpl applyTransformMatrix(
Matrix transformMatrix, int newWidth, int newHeight) {
return applyTransformMatrix(transformMatrix, /* unscaledWidth= */ newWidth,
/* unscaledHeight= */ newHeight, /* scaledWidth= */ newWidth,
/* scaledHeight= */ newHeight);
}
private TextureBufferImpl applyTransformMatrix(Matrix transformMatrix, int unscaledWidth,
int unscaledHeight, int scaledWidth, int scaledHeight) {
final Matrix newMatrix = new Matrix(this.transformMatrix);
newMatrix.preConcat(transformMatrix);
retain();
return new TextureBufferImpl(unscaledWidth, unscaledHeight, scaledWidth, scaledHeight, type, id,
newMatrix, toI420Handler, yuvConverter, new RefCountMonitor() {
@Override
public void onRetain(TextureBufferImpl textureBuffer) {
refCountMonitor.onRetain(TextureBufferImpl.this);
}
@Override
public void onRelease(TextureBufferImpl textureBuffer) {
refCountMonitor.onRelease(TextureBufferImpl.this);
}
@Override
public void onDestroy(TextureBufferImpl textureBuffer) {
release();
}
});
}
}
|