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