From b6441a02f5eb8a8377e90db1b392ae2ad9b372e1 Mon Sep 17 00:00:00 2001 From: sofijajvc Date: Mon, 5 Aug 2019 16:40:20 +0100 Subject: [PATCH] Introduce common output buffer class for video decoders PiperOrigin-RevId: 261693054 --- .../exoplayer2/ext/vp9/VpxOutputBuffer.java | 113 +--------------- .../video/VideoDecoderOutputBuffer.java | 125 ++++++++++++++++++ 2 files changed, 128 insertions(+), 110 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/video/VideoDecoderOutputBuffer.java diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java index de411089ab..7177cde12e 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java @@ -15,39 +15,12 @@ */ package com.google.android.exoplayer2.ext.vp9; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.decoder.OutputBuffer; -import com.google.android.exoplayer2.video.ColorInfo; -import java.nio.ByteBuffer; +import com.google.android.exoplayer2.video.VideoDecoderOutputBuffer; -/** Output buffer containing video frame data, populated by {@link VpxDecoder}. */ -public final class VpxOutputBuffer extends OutputBuffer { - - public static final int COLORSPACE_UNKNOWN = 0; - public static final int COLORSPACE_BT601 = 1; - public static final int COLORSPACE_BT709 = 2; - public static final int COLORSPACE_BT2020 = 3; +/** Video output buffer, populated by {@link VpxDecoder}. */ +public final class VpxOutputBuffer extends VideoDecoderOutputBuffer { private final VpxDecoder owner; - /** Decoder private data. */ - public int decoderPrivate; - - /** Output mode. */ - @C.VideoOutputMode public int mode; - /** - * RGB buffer for RGB mode. - */ - public ByteBuffer data; - public int width; - public int height; - public ColorInfo colorInfo; - - /** - * YUV planes for YUV mode. - */ - public ByteBuffer[] yuvPlanes; - public int[] yuvStrides; - public int colorspace; public VpxOutputBuffer(VpxDecoder owner) { this.owner = owner; @@ -58,84 +31,4 @@ public final class VpxOutputBuffer extends OutputBuffer { owner.releaseOutputBuffer(this); } - /** - * Initializes the buffer. - * - * @param timeUs The presentation timestamp for the buffer, in microseconds. - * @param mode The output mode. One of {@link C#VIDEO_OUTPUT_MODE_NONE}, {@link - * C#VIDEO_OUTPUT_MODE_YUV} and {@link C#VIDEO_OUTPUT_MODE_SURFACE_YUV}. - */ - public void init(long timeUs, @C.VideoOutputMode int mode) { - this.timeUs = timeUs; - this.mode = mode; - } - - /** - * Resizes the buffer based on the given stride. Called via JNI after decoding completes. - * - * @return Whether the buffer was resized successfully. - */ - public boolean initForYuvFrame(int width, int height, int yStride, int uvStride, int colorspace) { - this.width = width; - this.height = height; - this.colorspace = colorspace; - int uvHeight = (int) (((long) height + 1) / 2); - if (!isSafeToMultiply(yStride, height) || !isSafeToMultiply(uvStride, uvHeight)) { - return false; - } - int yLength = yStride * height; - int uvLength = uvStride * uvHeight; - int minimumYuvSize = yLength + (uvLength * 2); - if (!isSafeToMultiply(uvLength, 2) || minimumYuvSize < yLength) { - return false; - } - initData(minimumYuvSize); - - if (yuvPlanes == null) { - yuvPlanes = new ByteBuffer[3]; - } - // Rewrapping has to be done on every frame since the stride might have changed. - yuvPlanes[0] = data.slice(); - yuvPlanes[0].limit(yLength); - data.position(yLength); - yuvPlanes[1] = data.slice(); - yuvPlanes[1].limit(uvLength); - data.position(yLength + uvLength); - yuvPlanes[2] = data.slice(); - yuvPlanes[2].limit(uvLength); - if (yuvStrides == null) { - yuvStrides = new int[3]; - } - yuvStrides[0] = yStride; - yuvStrides[1] = uvStride; - yuvStrides[2] = uvStride; - return true; - } - - /** - * Configures the buffer for the given frame dimensions when passing actual frame data via {@link - * #decoderPrivate}. Called via JNI after decoding completes. - */ - public void initForPrivateFrame(int width, int height) { - this.width = width; - this.height = height; - } - - private void initData(int size) { - if (data == null || data.capacity() < size) { - data = ByteBuffer.allocateDirect(size); - } else { - data.position(0); - data.limit(size); - } - } - - /** - * Ensures that the result of multiplying individual numbers can fit into the size limit of an - * integer. - */ - private boolean isSafeToMultiply(int a, int b) { - return a >= 0 && b >= 0 && !(b > 0 && a >= Integer.MAX_VALUE / b); - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoDecoderOutputBuffer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoDecoderOutputBuffer.java new file mode 100644 index 0000000000..af0844defb --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoDecoderOutputBuffer.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.video; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.decoder.OutputBuffer; +import java.nio.ByteBuffer; + +/** Video decoder output buffer containing video frame data. */ +public abstract class VideoDecoderOutputBuffer extends OutputBuffer { + + public static final int COLORSPACE_UNKNOWN = 0; + public static final int COLORSPACE_BT601 = 1; + public static final int COLORSPACE_BT709 = 2; + public static final int COLORSPACE_BT2020 = 3; + + /** Decoder private data. */ + public int decoderPrivate; + + /** Output mode. */ + @C.VideoOutputMode public int mode; + /** RGB buffer for RGB mode. */ + public ByteBuffer data; + + public int width; + public int height; + public ColorInfo colorInfo; + + /** YUV planes for YUV mode. */ + public ByteBuffer[] yuvPlanes; + + public int[] yuvStrides; + public int colorspace; + + /** + * Initializes the buffer. + * + * @param timeUs The presentation timestamp for the buffer, in microseconds. + * @param mode The output mode. One of {@link C#VIDEO_OUTPUT_MODE_NONE}, {@link + * C#VIDEO_OUTPUT_MODE_YUV} and {@link C#VIDEO_OUTPUT_MODE_SURFACE_YUV}. + */ + public void init(long timeUs, @C.VideoOutputMode int mode) { + this.timeUs = timeUs; + this.mode = mode; + } + + /** + * Resizes the buffer based on the given stride. Called via JNI after decoding completes. + * + * @return Whether the buffer was resized successfully. + */ + public boolean initForYuvFrame(int width, int height, int yStride, int uvStride, int colorspace) { + this.width = width; + this.height = height; + this.colorspace = colorspace; + int uvHeight = (int) (((long) height + 1) / 2); + if (!isSafeToMultiply(yStride, height) || !isSafeToMultiply(uvStride, uvHeight)) { + return false; + } + int yLength = yStride * height; + int uvLength = uvStride * uvHeight; + int minimumYuvSize = yLength + (uvLength * 2); + if (!isSafeToMultiply(uvLength, 2) || minimumYuvSize < yLength) { + return false; + } + + // Initialize data. + if (data == null || data.capacity() < minimumYuvSize) { + data = ByteBuffer.allocateDirect(minimumYuvSize); + } else { + data.position(0); + data.limit(minimumYuvSize); + } + + if (yuvPlanes == null) { + yuvPlanes = new ByteBuffer[3]; + } + // Rewrapping has to be done on every frame since the stride might have changed. + yuvPlanes[0] = data.slice(); + yuvPlanes[0].limit(yLength); + data.position(yLength); + yuvPlanes[1] = data.slice(); + yuvPlanes[1].limit(uvLength); + data.position(yLength + uvLength); + yuvPlanes[2] = data.slice(); + yuvPlanes[2].limit(uvLength); + if (yuvStrides == null) { + yuvStrides = new int[3]; + } + yuvStrides[0] = yStride; + yuvStrides[1] = uvStride; + yuvStrides[2] = uvStride; + return true; + } + + /** + * Configures the buffer for the given frame dimensions when passing actual frame data via {@link + * #decoderPrivate}. Called via JNI after decoding completes. + */ + public void initForPrivateFrame(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Ensures that the result of multiplying individual numbers can fit into the size limit of an + * integer. + */ + private static boolean isSafeToMultiply(int a, int b) { + return a >= 0 && b >= 0 && !(b > 0 && a >= Integer.MAX_VALUE / b); + } +}