• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
11 package org.webrtc;
12 
13 import android.graphics.Matrix;
14 import android.opengl.GLES11Ext;
15 import android.opengl.GLES20;
16 import androidx.annotation.Nullable;
17 import java.nio.ByteBuffer;
18 
19 /**
20  * Java version of webrtc::VideoFrame and webrtc::VideoFrameBuffer. A difference from the C++
21  * version is that no explicit tag is used, and clients are expected to use 'instanceof' to find the
22  * right subclass of the buffer. This allows clients to create custom VideoFrame.Buffer in
23  * arbitrary format in their custom VideoSources, and then cast it back to the correct subclass in
24  * their custom VideoSinks. All implementations must also implement the toI420() function,
25  * converting from the underlying representation if necessary. I420 is the most widely accepted
26  * format and serves as a fallback for video sinks that can only handle I420, e.g. the internal
27  * WebRTC software encoders.
28  */
29 public class VideoFrame implements RefCounted {
30   /**
31    * Implements image storage medium. Might be for example an OpenGL texture or a memory region
32    * containing I420-data.
33    *
34    * <p>Reference counting is needed since a video buffer can be shared between multiple VideoSinks,
35    * and the buffer needs to be returned to the VideoSource as soon as all references are gone.
36    */
37   public interface Buffer extends RefCounted {
38     /**
39      * Representation of the underlying buffer. Currently, only NATIVE and I420 are supported.
40      */
41     @CalledByNative("Buffer")
42     @VideoFrameBufferType
getBufferType()43     default int getBufferType() {
44       return VideoFrameBufferType.NATIVE;
45     }
46 
47     /**
48      * Resolution of the buffer in pixels.
49      */
getWidth()50     @CalledByNative("Buffer") int getWidth();
getHeight()51     @CalledByNative("Buffer") int getHeight();
52 
53     /**
54      * Returns a memory-backed frame in I420 format. If the pixel data is in another format, a
55      * conversion will take place. All implementations must provide a fallback to I420 for
56      * compatibility with e.g. the internal WebRTC software encoders.
57      *
58      * <p> Conversion may fail, for example if reading the pixel data from a texture fails. If the
59      * conversion fails, null is returned.
60      */
toI420()61     @Nullable @CalledByNative("Buffer") I420Buffer toI420();
62 
retain()63     @Override @CalledByNative("Buffer") void retain();
release()64     @Override @CalledByNative("Buffer") void release();
65 
66     /**
67      * Crops a region defined by `cropx`, `cropY`, `cropWidth` and `cropHeight`. Scales it to size
68      * `scaleWidth` x `scaleHeight`.
69      */
70     @CalledByNative("Buffer")
cropAndScale( int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight)71     Buffer cropAndScale(
72         int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight);
73   }
74 
75   /**
76    * Interface for I420 buffers.
77    */
78   public interface I420Buffer extends Buffer {
79     @Override
getBufferType()80     default int getBufferType() {
81       return VideoFrameBufferType.I420;
82     }
83 
84     /**
85      * Returns a direct ByteBuffer containing Y-plane data. The buffer capacity is at least
86      * getStrideY() * getHeight() bytes. The position of the returned buffer is ignored and must
87      * be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
88      * implementations must return a new ByteBuffer or slice for each call.
89      */
getDataY()90     @CalledByNative("I420Buffer") ByteBuffer getDataY();
91     /**
92      * Returns a direct ByteBuffer containing U-plane data. The buffer capacity is at least
93      * getStrideU() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored
94      * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
95      * implementations must return a new ByteBuffer or slice for each call.
96      */
getDataU()97     @CalledByNative("I420Buffer") ByteBuffer getDataU();
98     /**
99      * Returns a direct ByteBuffer containing V-plane data. The buffer capacity is at least
100      * getStrideV() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored
101      * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
102      * implementations must return a new ByteBuffer or slice for each call.
103      */
getDataV()104     @CalledByNative("I420Buffer") ByteBuffer getDataV();
105 
getStrideY()106     @CalledByNative("I420Buffer") int getStrideY();
getStrideU()107     @CalledByNative("I420Buffer") int getStrideU();
getStrideV()108     @CalledByNative("I420Buffer") int getStrideV();
109   }
110 
111   /**
112    * Interface for buffers that are stored as a single texture, either in OES or RGB format.
113    */
114   public interface TextureBuffer extends Buffer {
115     enum Type {
116       OES(GLES11Ext.GL_TEXTURE_EXTERNAL_OES),
117       RGB(GLES20.GL_TEXTURE_2D);
118 
119       private final int glTarget;
120 
Type(final int glTarget)121       private Type(final int glTarget) {
122         this.glTarget = glTarget;
123       }
124 
getGlTarget()125       public int getGlTarget() {
126         return glTarget;
127       }
128     }
129 
getType()130     Type getType();
getTextureId()131     int getTextureId();
132 
133     /**
134      * Retrieve the transform matrix associated with the frame. This transform matrix maps 2D
135      * homogeneous coordinates of the form (s, t, 1) with s and t in the inclusive range [0, 1] to
136      * the coordinate that should be used to sample that location from the buffer.
137      */
getTransformMatrix()138     Matrix getTransformMatrix();
139 
140     /**
141      * Create a new TextureBufferImpl with an applied transform matrix and a new size. The existing
142      * buffer is unchanged. The given transform matrix is applied first when texture coordinates are
143      * still in the unmodified [0, 1] range.
144      */
applyTransformMatrix( Matrix transformMatrix, int newWidth, int newHeight)145     default TextureBuffer applyTransformMatrix(
146         Matrix transformMatrix, int newWidth, int newHeight) {
147       throw new UnsupportedOperationException("Not implemented");
148     }
149   }
150 
151   private final Buffer buffer;
152   private final int rotation;
153   private final long timestampNs;
154 
155   /**
156    * Constructs a new VideoFrame backed by the given {@code buffer}.
157    *
158    * @note Ownership of the buffer object is tranferred to the new VideoFrame.
159    */
160   @CalledByNative
VideoFrame(Buffer buffer, int rotation, long timestampNs)161   public VideoFrame(Buffer buffer, int rotation, long timestampNs) {
162     if (buffer == null) {
163       throw new IllegalArgumentException("buffer not allowed to be null");
164     }
165     if (rotation % 90 != 0) {
166       throw new IllegalArgumentException("rotation must be a multiple of 90");
167     }
168     this.buffer = buffer;
169     this.rotation = rotation;
170     this.timestampNs = timestampNs;
171   }
172 
173   @CalledByNative
getBuffer()174   public Buffer getBuffer() {
175     return buffer;
176   }
177 
178   /**
179    * Rotation of the frame in degrees.
180    */
181   @CalledByNative
getRotation()182   public int getRotation() {
183     return rotation;
184   }
185 
186   /**
187    * Timestamp of the frame in nano seconds.
188    */
189   @CalledByNative
getTimestampNs()190   public long getTimestampNs() {
191     return timestampNs;
192   }
193 
getRotatedWidth()194   public int getRotatedWidth() {
195     if (rotation % 180 == 0) {
196       return buffer.getWidth();
197     }
198     return buffer.getHeight();
199   }
200 
getRotatedHeight()201   public int getRotatedHeight() {
202     if (rotation % 180 == 0) {
203       return buffer.getHeight();
204     }
205     return buffer.getWidth();
206   }
207 
208   @Override
retain()209   public void retain() {
210     buffer.retain();
211   }
212 
213   @Override
214   @CalledByNative
release()215   public void release() {
216     buffer.release();
217   }
218 }
219