1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2012 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw.decoder; 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.annotation.TargetApi; 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.SurfaceTexture; 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.SurfaceTexture.OnFrameAvailableListener; 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec; 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec.BufferInfo; 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaFormat; 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.Surface; 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameImage2D; 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.ImageShader; 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.TextureSource; 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 3183511d2f49c9e272f328730586c3d0a7852247f2Andy Hungimport java.io.IOException; 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer; 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/** 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link TrackDecoder} that decodes a video track and renders the frames onto a 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link SurfaceTexture}. 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This implementation uses the GPU for image operations such as copying 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * and color-space conversion. 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks@TargetApi(16) 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class GpuVideoTrackDecoder extends VideoTrackDecoder { 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Identity fragment shader for external textures. 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static final String COPY_FRAGMENT_SHADER = 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "#extension GL_OES_EGL_image_external : require\n" + 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "precision mediump float;\n" + 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "uniform samplerExternalOES tex_sampler_0;\n" + 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_texcoord;\n" + 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "void main() {\n" + 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}\n"; 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final TextureSource mTextureSource; 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final SurfaceTexture mSurfaceTexture; // Access guarded by mFrameMonitor. 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final float[] mTransformMatrix; 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final int mOutputWidth; 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final int mOutputHeight; 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private ImageShader mImageShader; 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private long mCurrentPresentationTimeUs; 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public GpuVideoTrackDecoder( 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int trackIndex, MediaFormat format, Listener listener) { 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super(trackIndex, format, listener); 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Create a surface texture to be used by the video track decoder. 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTextureSource = TextureSource.newExternalTexture(); 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture = new SurfaceTexture(mTextureSource.getTextureId()); 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.detachFromGLContext(); 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.setOnFrameAvailableListener(new OnFrameAvailableListener() { 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onFrameAvailable(SurfaceTexture surfaceTexture) { 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks markFrameAvailable(); 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }); 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutputWidth = format.getInteger(MediaFormat.KEY_WIDTH); 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutputHeight = format.getInteger(MediaFormat.KEY_HEIGHT); 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTransformMatrix = new float[16]; 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected MediaCodec initMediaCodec(MediaFormat format) { 9083511d2f49c9e272f328730586c3d0a7852247f2Andy Hung MediaCodec mediaCodec; 9183511d2f49c9e272f328730586c3d0a7852247f2Andy Hung try { 9283511d2f49c9e272f328730586c3d0a7852247f2Andy Hung mediaCodec = MediaCodec.createDecoderByType( 9383511d2f49c9e272f328730586c3d0a7852247f2Andy Hung format.getString(MediaFormat.KEY_MIME)); 9483511d2f49c9e272f328730586c3d0a7852247f2Andy Hung } catch (IOException e) { 9583511d2f49c9e272f328730586c3d0a7852247f2Andy Hung throw new RuntimeException( 9683511d2f49c9e272f328730586c3d0a7852247f2Andy Hung "failed to create decoder for " 9783511d2f49c9e272f328730586c3d0a7852247f2Andy Hung + format.getString(MediaFormat.KEY_MIME), e); 9883511d2f49c9e272f328730586c3d0a7852247f2Andy Hung } 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Surface surface = new Surface(mSurfaceTexture); 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mediaCodec.configure(format, surface, null, 0); 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surface.release(); 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mediaCodec; 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected boolean onDataAvailable( 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info) { 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks boolean textureAvailable = waitForFrameGrab(); 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCurrentPresentationTimeUs = info.presentationTimeUs; 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Only render the next frame if we weren't interrupted. 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks codec.releaseOutputBuffer(bufferIndex, textureAvailable); 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (textureAvailable) { 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (updateTexture()) { 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks notifyListener(); 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Waits for the texture's {@link OnFrameAvailableListener} to be notified and then updates 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the internal {@link SurfaceTexture}. 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private boolean updateTexture() { 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Wait for the frame we just released to appear in the texture. 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mFrameMonitor) { 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks while (!mFrameAvailable) { 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFrameMonitor.wait(); 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.attachToGLContext(mTextureSource.getTextureId()); 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.updateTexImage(); 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.detachFromGLContext(); 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void copyFrameDataTo(FrameImage2D outputVideoFrame, int rotation) { 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource targetTexture = TextureSource.newExternalTexture(); 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.attachToGLContext(targetTexture.getTextureId()); 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.getTransformMatrix(mTransformMatrix); 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader imageShader = getImageShader(); 152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks imageShader.setSourceTransform(mTransformMatrix); 153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int outputWidth = mOutputWidth; 155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int outputHeight = mOutputHeight; 156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (rotation != 0) { 157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float[] targetCoords = getRotationCoords(rotation); 158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks imageShader.setTargetCoords(targetCoords); 159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (needSwapDimension(rotation)) { 160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputWidth = mOutputHeight; 161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputHeight = mOutputWidth; 162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputVideoFrame.resize(new int[] { outputWidth, outputHeight }); 165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks imageShader.process( 166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetTexture, 167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputVideoFrame.lockRenderTarget(), 168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputWidth, 169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputHeight); 170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputVideoFrame.setTimestamp(mCurrentPresentationTimeUs * 1000); 171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks outputVideoFrame.unlock(); 172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetTexture.release(); 173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.detachFromGLContext(); 175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void release() { 179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.release(); 180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mFrameMonitor) { 181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTextureSource.release(); 182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceTexture.release(); 183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /* 187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This method has to be called on the MFF processing thread. 188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private ImageShader getImageShader() { 190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mImageShader == null) { 191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mImageShader = new ImageShader(COPY_FRAGMENT_SHADER); 192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mImageShader.setTargetRect(0f, 1f, 1f, -1f); 193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mImageShader; 195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the quad coords for rotation. 199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param rotation applied to the frame, value is one of 200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {ROTATE_NONE, ROTATE_90_RIGHT, ROTATE_180, ROTATE_90_LEFT} 201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return coords the calculated quad coords for the given rotation 202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static float[] getRotationCoords(int rotation) { 204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch(rotation) { 205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case MediaDecoder.ROTATE_90_RIGHT: 206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new float[] { 0f, 0f, 0f, 1f, 1f, 0f, 1f, 1f }; 207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case MediaDecoder.ROTATE_180: 208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new float[] { 1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f }; 209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case MediaDecoder.ROTATE_90_LEFT: 210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new float[] { 1f, 1f, 1f, 0f, 0f, 1f, 0f, 0f }; 211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case MediaDecoder.ROTATE_NONE: 212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new float[] { 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f }; 213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks default: 214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Unsupported rotation angle."); 215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 219