blob: 5d98a291a3b2066954e0adf7dc27784e12dcc79b [file] [log] [blame]
magjed55220212017-06-02 02:45:56 -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;
Sami Kalliomäkicb98b112017-10-16 11:20:26 +020014import android.opengl.GLES11Ext;
15import android.opengl.GLES20;
Artem Titarenko69540f42018-12-10 12:30:46 +010016import android.support.annotation.Nullable;
magjed55220212017-06-02 02:45:56 -070017import 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 */
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020029public 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 {
magjed55220212017-06-02 02:45:56 -070038 /**
39 * Resolution of the buffer in pixels.
40 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010041 @CalledByNative("Buffer") int getWidth();
42 @CalledByNative("Buffer") int getHeight();
magjed55220212017-06-02 02:45:56 -070043
44 /**
45 * Returns a memory-backed frame in I420 format. If the pixel data is in another format, a
46 * conversion will take place. All implementations must provide a fallback to I420 for
47 * compatibility with e.g. the internal WebRTC software encoders.
48 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010049 @CalledByNative("Buffer") I420Buffer toI420();
magjed55220212017-06-02 02:45:56 -070050
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +020051 @Override @CalledByNative("Buffer") void retain();
52 @Override @CalledByNative("Buffer") void release();
sakal836f60c2017-07-28 07:12:23 -070053
54 /**
55 * Crops a region defined by |cropx|, |cropY|, |cropWidth| and |cropHeight|. Scales it to size
56 * |scaleWidth| x |scaleHeight|.
57 */
Magnus Jedvert202be392017-11-18 16:09:17 +010058 @CalledByNative("Buffer")
sakal836f60c2017-07-28 07:12:23 -070059 Buffer cropAndScale(
60 int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight);
magjed55220212017-06-02 02:45:56 -070061 }
62
63 /**
64 * Interface for I420 buffers.
65 */
66 public interface I420Buffer extends Buffer {
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020067 /**
Sami Kalliomäkie3044fe2017-10-02 09:41:55 +020068 * Returns a direct ByteBuffer containing Y-plane data. The buffer capacity is at least
69 * getStrideY() * getHeight() bytes. The position of the returned buffer is ignored and must
70 * be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
71 * implementations must return a new ByteBuffer or slice for each call.
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020072 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010073 @CalledByNative("I420Buffer") ByteBuffer getDataY();
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020074 /**
Sami Kalliomäkie3044fe2017-10-02 09:41:55 +020075 * Returns a direct ByteBuffer containing U-plane data. The buffer capacity is at least
76 * getStrideU() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored
77 * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
78 * implementations must return a new ByteBuffer or slice for each call.
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020079 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010080 @CalledByNative("I420Buffer") ByteBuffer getDataU();
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020081 /**
Sami Kalliomäkie3044fe2017-10-02 09:41:55 +020082 * Returns a direct ByteBuffer containing V-plane data. The buffer capacity is at least
83 * getStrideV() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored
84 * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so
85 * implementations must return a new ByteBuffer or slice for each call.
Sami Kalliomäkibc7a1a92017-09-27 12:50:47 +020086 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010087 @CalledByNative("I420Buffer") ByteBuffer getDataV();
magjed55220212017-06-02 02:45:56 -070088
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010089 @CalledByNative("I420Buffer") int getStrideY();
90 @CalledByNative("I420Buffer") int getStrideU();
91 @CalledByNative("I420Buffer") int getStrideV();
magjed55220212017-06-02 02:45:56 -070092 }
93
94 /**
95 * Interface for buffers that are stored as a single texture, either in OES or RGB format.
96 */
97 public interface TextureBuffer extends Buffer {
Sami Kalliomäkicb98b112017-10-16 11:20:26 +020098 enum Type {
99 OES(GLES11Ext.GL_TEXTURE_EXTERNAL_OES),
100 RGB(GLES20.GL_TEXTURE_2D);
101
102 private final int glTarget;
103
104 private Type(final int glTarget) {
105 this.glTarget = glTarget;
106 }
107
108 public int getGlTarget() {
109 return glTarget;
110 }
111 }
magjed55220212017-06-02 02:45:56 -0700112
113 Type getType();
114 int getTextureId();
sakal836f60c2017-07-28 07:12:23 -0700115
116 /**
117 * Retrieve the transform matrix associated with the frame. This transform matrix maps 2D
118 * homogeneous coordinates of the form (s, t, 1) with s and t in the inclusive range [0, 1] to
119 * the coordinate that should be used to sample that location from the buffer.
120 */
Magnus Jedvert783c6e32018-07-05 13:34:17 +0200121 Matrix getTransformMatrix();
magjed55220212017-06-02 02:45:56 -0700122 }
123
124 private final Buffer buffer;
125 private final int rotation;
126 private final long timestampNs;
magjed55220212017-06-02 02:45:56 -0700127
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200128 /**
129 * Constructs a new VideoFrame backed by the given {@code buffer}.
130 *
131 * @note Ownership of the buffer object is tranferred to the new VideoFrame.
132 */
Magnus Jedvert1f2a3e72017-11-23 16:56:44 +0100133 @CalledByNative
sakal836f60c2017-07-28 07:12:23 -0700134 public VideoFrame(Buffer buffer, int rotation, long timestampNs) {
magjed55220212017-06-02 02:45:56 -0700135 if (buffer == null) {
136 throw new IllegalArgumentException("buffer not allowed to be null");
137 }
sakal6bdcefc2017-08-15 01:56:02 -0700138 if (rotation % 90 != 0) {
139 throw new IllegalArgumentException("rotation must be a multiple of 90");
140 }
magjed55220212017-06-02 02:45:56 -0700141 this.buffer = buffer;
142 this.rotation = rotation;
143 this.timestampNs = timestampNs;
magjed55220212017-06-02 02:45:56 -0700144 }
145
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +0100146 @CalledByNative
magjed55220212017-06-02 02:45:56 -0700147 public Buffer getBuffer() {
148 return buffer;
149 }
150
151 /**
152 * Rotation of the frame in degrees.
153 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +0100154 @CalledByNative
magjed55220212017-06-02 02:45:56 -0700155 public int getRotation() {
156 return rotation;
157 }
158
159 /**
160 * Timestamp of the frame in nano seconds.
161 */
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +0100162 @CalledByNative
magjed55220212017-06-02 02:45:56 -0700163 public long getTimestampNs() {
164 return timestampNs;
165 }
166
sakal6bdcefc2017-08-15 01:56:02 -0700167 public int getRotatedWidth() {
168 if (rotation % 180 == 0) {
169 return buffer.getWidth();
170 }
171 return buffer.getHeight();
172 }
173
174 public int getRotatedHeight() {
175 if (rotation % 180 == 0) {
176 return buffer.getHeight();
177 }
178 return buffer.getWidth();
179 }
180
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200181 @Override
magjed55220212017-06-02 02:45:56 -0700182 public void retain() {
183 buffer.retain();
184 }
185
Sami Kalliomäki61db3fd2018-04-09 17:51:19 +0200186 @Override
Sami Kalliomäki2bde8502018-02-15 13:58:15 +0100187 @CalledByNative
magjed55220212017-06-02 02:45:56 -0700188 public void release() {
189 buffer.release();
190 }
magjed55220212017-06-02 02:45:56 -0700191}