public class VideoFrame implements RefCounted {
+
public interface Buffer extends RefCounted {
- @CalledByNative("Buffer") int getWidth();
- @CalledByNative("Buffer") int getHeight();
- @CalledByNative("Buffer") I420Buffer toI420();
- @Override @CalledByNative("Buffer") void release();
- @Override @CalledByNative("Buffer") void retain();
- @CalledByNative("Buffer")
+
+ @CalledByNative("Buffer") int getWidth();
+
+ @CalledByNative("Buffer") int getHeight();
+
+ @CalledByNative("Buffer") I420Buffer toI420();
+
+ @Override @CalledByNative("Buffer") void release();
+
+ @Override @CalledByNative("Buffer") void retain();
+
+ @CalledByNative("Buffer")
Buffer cropAndScale(
int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight);
- @CalledByNative("Buffer") @Nullable Buffer mirror(int frameRotation);
- @CalledByNative("Buffer") @Nullable Buffer rotate(int frameRotation);
- @CalledByNative("Buffer")
+
+ @CalledByNative("Buffer") @Nullable Buffer mirror(int frameRotation);
+
+ @CalledByNative("Buffer") @Nullable Buffer rotate(int frameRotation);
+
+ @CalledByNative("Buffer")
@Nullable
Buffer transform(int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth,
int scaleHeight, int frameRotation);
}
+
public interface I420Buffer extends Buffer {
- @CalledByNative("I420Buffer") ByteBuffer getDataY();
- @CalledByNative("I420Buffer") ByteBuffer getDataU();
- @CalledByNative("I420Buffer") ByteBuffer getDataV();
- @CalledByNative("I420Buffer") int getStrideY();
- @CalledByNative("I420Buffer") int getStrideU();
- @CalledByNative("I420Buffer") int getStrideV();
+
+ @CalledByNative("I420Buffer") ByteBuffer getDataY();
+
+ @CalledByNative("I420Buffer") ByteBuffer getDataU();
+
+ @CalledByNative("I420Buffer") ByteBuffer getDataV();
+ @CalledByNative("I420Buffer") int getStrideY();
+ @CalledByNative("I420Buffer") int getStrideU();
+ @CalledByNative("I420Buffer") int getStrideV();
}
+
public interface I422Buffer extends Buffer {
- @CalledByNative("I422Buffer") ByteBuffer getDataY();
- @CalledByNative("I422Buffer") ByteBuffer getDataU();
- @CalledByNative("I422Buffer") ByteBuffer getDataV();
- @CalledByNative("I422Buffer") int getStrideY();
- @CalledByNative("I422Buffer") int getStrideU();
- @CalledByNative("I422Buffer") int getStrideV();
- }
- public interface RgbaBuffer extends Buffer { @CalledByNative("RgbaBuffer") ByteBuffer getData(); }
+ @CalledByNative("I422Buffer") ByteBuffer getDataY();
+ @CalledByNative("I422Buffer") ByteBuffer getDataU();
+ @CalledByNative("I422Buffer") ByteBuffer getDataV();
+ @CalledByNative("I422Buffer") int getStrideY();
+ @CalledByNative("I422Buffer") int getStrideU();
+ @CalledByNative("I422Buffer") int getStrideV();
+ }
+ public interface RgbaBuffer extends Buffer { @CalledByNative("RgbaBuffer") ByteBuffer getData(); }
+
public interface TextureBuffer extends Buffer {
+
enum Type {
+
OES(GLES11Ext.GL_TEXTURE_EXTERNAL_OES),
+
RGB(GLES20.GL_TEXTURE_2D);
private final int glTarget;
private Type(final int glTarget) {
@@ -57,22 +76,26 @@
EGL_CONTEXT_14;
}
Type getType();
- @CalledByNative("TextureBuffer") int getTextureId();
+
+ @CalledByNative("TextureBuffer") int getTextureId();
+
Matrix getTransformMatrix();
- @CalledByNative("TextureBuffer") EglBase.Context getEglBaseContext();
- @CalledByNative("TextureBuffer") Object getSourceTexturePool();
- @CalledByNative("TextureBuffer") long getNativeEglContext();
- @CalledByNative("TextureBuffer") int getEglContextType();
- @CalledByNative("TextureBuffer") float[] getTransformMatrixArray();
- @CalledByNative("TextureBuffer") int getSequence();
- @CalledByNative("TextureBuffer") boolean is10BitTexture();
+
+ @CalledByNative("TextureBuffer") EglBase.Context getEglBaseContext();
+ @CalledByNative("TextureBuffer") Object getSourceTexturePool();
+ @CalledByNative("TextureBuffer") long getNativeEglContext();
+ @CalledByNative("TextureBuffer") int getEglContextType();
+ @CalledByNative("TextureBuffer") float[] getTransformMatrixArray();
+
+ @CalledByNative("TextureBuffer") int getSequence();
+ @CalledByNative("TextureBuffer") long getFenceObject();
+ @CalledByNative("TextureBuffer") boolean is10BitTexture();
}
public interface ColorSpace {
enum Range {
Invalid(0),
Limited(1),
- Full(2),
- Derived(3);
+ Full(2);
private final int range;
private Range(int range) {
this.range = range;
@@ -161,32 +184,55 @@
kBackCamera,
kUnspecified,
}
+ public enum AlphaStitchMode {
+ ALPHA_NO_STITCH(0),
+ ALPHA_STITCH_UP(1),
+ ALPHA_STITCH_BELOW(2),
+ ALPHA_STITCH_LEFT(3),
+ ALPHA_STITCH_RIGHT(4);
+ private final int stitchMode;
+ private AlphaStitchMode(int stitchMode) {
+ this.stitchMode = stitchMode;
+ }
+ public int value() {
+ return stitchMode;
+ }
+ }
+
private Buffer buffer;
+
private int rotation;
+
private long timestampNs;
private ColorSpace colorSpace;
private SourceType sourceType;
private float sampleAspectRatio;
+
+ private AlphaStitchMode alphaStitchMode = AlphaStitchMode.ALPHA_NO_STITCH;
private VideoFrameMetaInfo metaInfo = new VideoFrameMetaInfo();
+
private @Nullable ByteBuffer alphaBuffer;
- private int alphaStitchMode;
+ private long nativeAlphaBuffer;
+
public VideoFrame(Buffer buffer, int rotation, long timestampNs) {
- this(buffer, rotation, timestampNs, new WrappedNativeColorSpace(), null, 0L, 1.0f, SourceType.kUnspecified.ordinal());
+ this(buffer, rotation, timestampNs, new WrappedNativeColorSpace(), null, 0L, 1.0f,
+ SourceType.kUnspecified.ordinal());
}
@CalledByNative
public VideoFrame(Buffer buffer, int rotation, long timestampNs, ColorSpace colorSpace,
- ByteBuffer alphaBuffer, float sampleAspectRatio, int sourceType) {
+ ByteBuffer alphaBuffer, long nativeAlphaBuffer, float sampleAspectRatio, int sourceType) {
if (buffer == null) {
- throw new IllegalArgumentException("buffer not allowed to be null");
+ throw new IllegalArgumentException("buffer not allowed to be null");
}
if (rotation % 90 != 0) {
- throw new IllegalArgumentException("rotation must be a multiple of 90");
+ throw new IllegalArgumentException("rotation must be a multiple of 90");
}
this.buffer = buffer;
this.rotation = rotation;
this.timestampNs = timestampNs;
this.colorSpace = colorSpace;
this.alphaBuffer = alphaBuffer;
+ this.nativeAlphaBuffer = nativeAlphaBuffer;
this.sampleAspectRatio = sampleAspectRatio;
this.sourceType = SourceType.values()[sourceType];
}
@@ -197,18 +243,25 @@
public float getSampleAspectRatio() {
return sampleAspectRatio;
}
+
@CalledByNative
public Buffer getBuffer() {
return buffer;
}
+
@CalledByNative
public int getRotation() {
return rotation;
}
@CalledByNative
public int getAlphaStitchMode() {
- return alphaStitchMode;
+ return alphaStitchMode.value();
}
+ @CalledByNative
+ public void setAlphaStitchMode(int stitchMode) {
+ alphaStitchMode = AlphaStitchMode.values()[stitchMode];
+ }
+
@CalledByNative
public long getTimestampNs() {
return timestampNs;
@@ -217,41 +270,93 @@
public VideoFrameMetaInfo getMetaInfo() {
return metaInfo;
}
+
public int getRotatedWidth() {
if (rotation % 180 == 0) {
- return buffer.getWidth();
+ return (alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_LEFT
+ || alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_RIGHT)
+ ? buffer.getWidth() / 2
+ : buffer.getWidth();
}
- return buffer.getHeight();
+ return (alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_UP
+ || alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_BELOW)
+ ? buffer.getHeight() / 2
+ : buffer.getHeight();
}
+
public int getRotatedHeight() {
if (rotation % 180 == 0) {
- return buffer.getHeight();
+ return (alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_UP
+ || alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_BELOW)
+ ? buffer.getHeight() / 2
+ : buffer.getHeight();
}
- return buffer.getWidth();
+ return (alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_LEFT
+ || alphaStitchMode == AlphaStitchMode.ALPHA_STITCH_RIGHT)
+ ? buffer.getWidth() / 2
+ : buffer.getWidth();
}
+
public void replaceBuffer(Buffer buffer, int rotation, long timestampNs) {
release();
this.buffer = buffer;
this.rotation = rotation;
this.timestampNs = timestampNs;
}
+ @CalledByNative
public ColorSpace getColorSpace() {
return colorSpace;
}
+ public void setColorSpace(ColorSpace colorSpace) {
+ this.colorSpace = colorSpace;
+ }
+ @CalledByNative
+ private int getColorSpaceRange() {
+ if (colorSpace == null) {
+ return ColorSpace.Range.Invalid.getRange();
+ }
+ return colorSpace.getRange().getRange();
+ }
+ @CalledByNative
+ private int getColorSpaceMatrix() {
+ if (colorSpace == null) {
+ return ColorSpace.Matrix.Unspecified.getMatrix();
+ }
+ return colorSpace.getMatrix().getMatrix();
+ }
+ @CalledByNative
+ private int getColorSpaceTransfer() {
+ if (colorSpace == null) {
+ return ColorSpace.Transfer.Unspecified.getTransfer();
+ }
+ return colorSpace.getTransfer().getTransfer();
+ }
+ @CalledByNative
+ private int getColorSpacePrimary() {
+ if (colorSpace == null) {
+ return ColorSpace.Primary.Unspecified.getPrimary();
+ }
+ return colorSpace.getPrimary().getPrimary();
+ }
@CalledByNative
public ByteBuffer getAlphaBuffer() {
return alphaBuffer;
}
+ public void retainAlphaBuffer() {
+ JniCommon.nativeAddRef(nativeAlphaBuffer);
+ }
+ public void releaseAlphaBuffer() {
+ JniCommon.nativeReleaseRef(nativeAlphaBuffer);
+ }
public void fillAlphaData(ByteBuffer buffer) {
alphaBuffer = buffer;
}
- public void setAlphaStitchMode(int mode) {
- this.alphaStitchMode = mode;
- }
+
@Override
public void retain() {
buffer.retain();
}
+
@Override
@CalledByNative
public void release() {
@@ -278,7 +383,8 @@
this.format = format;
}
}
- __attribute__((visibility("default"))) @interface AgoraOutputVideoFrame : NSObject
+ __attribute__((visibility("default"))) @interface AgoraOutputVideoFrame : NSObject
+
@property (nonatomic, assign) NSInteger type;
@property (nonatomic, assign) int width;
@property (nonatomic, assign) int height;
@@ -291,12 +397,16 @@
@property (nonatomic, assign) int rotation;
@property (nonatomic, assign) int64_t renderTimeMs;
@property (nonatomic, assign) int avSyncType;
+
@property(assign, nonatomic) CVPixelBufferRef _Nullable pixelBuffer;
@property (nonatomic, assign) uint8_t* _Nullable alphaBuffer;
@property (nonatomic, assign) AgoraAlphaStitchMode alphaStitchMode;
+
@property(nonatomic, strong) NSDictionary *_Nonnull metaInfo;
+@property(nonatomic, strong) AgoraColorSpace* _Nullable colorSpace;
@end
- struct VideoFrame {
+
+struct VideoFrame {
VideoFrame():
type(VIDEO_PIXEL_DEFAULT),
width(0),
@@ -316,33 +426,57 @@
textureId(0),
d3d11Texture2d(NULL),
alphaBuffer(NULL),
- alphaStitchMode(0),
+ alphaStitchMode(NO_ALPHA_STITCH),
pixelBuffer(NULL),
metaInfo(NULL){
memset(matrix, 0, sizeof(matrix));
}
+
VIDEO_PIXEL_FORMAT type;
+
int width;
+
int height;
+
int yStride;
+
int uStride;
+
int vStride;
+
uint8_t* yBuffer;
+
uint8_t* uBuffer;
+
uint8_t* vBuffer;
+
int rotation;
+
int64_t renderTimeMs;
+
int avsync_type;
+
uint8_t* metadata_buffer;
+
int metadata_size;
+
void* sharedContext;
+
int textureId;
+
void* d3d11Texture2d;
+
float matrix[16];
+
uint8_t* alphaBuffer;
- int alphaStitchMode;
+
+ ALPHA_STITCH_MODE alphaStitchMode;
+
void* pixelBuffer;
+
IVideoFrameMetaInfo* metaInfo;
+
+ ColorSpace colorSpace;
};
USTRUCT(BlueprintType)
struct FVideoFrame {
@@ -608,6 +742,19 @@ class VideoFrame {
缓冲区给出的是指向指针的指针,该接口不能修改缓冲区的指针,只能修改缓冲区的内容。
+
+ 方法
+
+
+ getColorSpace
+ 获取视频帧的色彩空间属性。
+
+
+ setColorSpace
+ 设置视频帧的色彩空间属性。
+
+
+
@@ -727,9 +874,9 @@ class VideoFrame {
pixelBuffer
将数据填充到 CVPixelBuffer。