1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright 2013 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 Hendrickspackage androidx.media.filterfw.decoder;
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.annotation.TargetApi;
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.SurfaceTexture;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodec.BufferInfo;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodecInfo;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodecInfo.CodecCapabilities;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaCodecList;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaFormat;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.SparseIntArray;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.ColorSpace;
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Frame;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameImage2D;
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.PixelUtils;
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
3283511d2f49c9e272f328730586c3d0a7852247f2Andy Hungimport java.io.IOException;
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer;
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Arrays;
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashSet;
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Set;
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.TreeMap;
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link TrackDecoder} that decodes a video track and renders the frames onto a
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link SurfaceTexture}.
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This implementation purely uses CPU based methods to decode and color-convert the frames.
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks@TargetApi(16)
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class CpuVideoTrackDecoder extends VideoTrackDecoder {
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final int COLOR_FORMAT_UNSET = -1;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final int mWidth;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final int mHeight;
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mColorFormat = COLOR_FORMAT_UNSET;
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private long mCurrentPresentationTimeUs;
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ByteBuffer mDecodedBuffer;
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ByteBuffer mUnrotatedBytes;
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected CpuVideoTrackDecoder(int trackIndex, MediaFormat format, Listener listener) {
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        super(trackIndex, format, listener);
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected MediaCodec initMediaCodec(MediaFormat format) {
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Find a codec for our video that can output to one of our supported color-spaces
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        MediaCodec mediaCodec = findDecoderCodec(format, new int[] {
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                CodecCapabilities.COLOR_Format32bitARGB8888,
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                CodecCapabilities.COLOR_FormatYUV420Planar});
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mediaCodec == null) {
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException(
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    "Could not find a suitable decoder for format: " + format + "!");
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mediaCodec.configure(format, null, null, 0);
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mediaCodec;
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected boolean onDataAvailable(
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info) {
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mCurrentPresentationTimeUs = info.presentationTimeUs;
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mDecodedBuffer = buffers[bufferIndex];
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mColorFormat == -1) {
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mColorFormat = codec.getOutputFormat().getInteger(MediaFormat.KEY_COLOR_FORMAT);
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        markFrameAvailable();
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        notifyListener();
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Wait for the grab before we release this buffer.
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        waitForFrameGrab();
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        codec.releaseOutputBuffer(bufferIndex, false);
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return false;
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void copyFrameDataTo(FrameImage2D outputVideoFrame, int rotation) {
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Calculate output dimensions
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int outputWidth = mWidth;
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int outputHeight = mHeight;
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (needSwapDimension(rotation)) {
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outputWidth = mHeight;
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outputHeight = mWidth;
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Create output frame
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outputVideoFrame.resize(new int[] {outputWidth, outputHeight});
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outputVideoFrame.setTimestamp(mCurrentPresentationTimeUs * 1000);
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ByteBuffer outBytes = outputVideoFrame.lockBytes(Frame.MODE_WRITE);
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Set data
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (rotation == MediaDecoder.ROTATE_NONE) {
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            convertImage(mDecodedBuffer, outBytes, mColorFormat, mWidth, mHeight);
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mUnrotatedBytes == null) {
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mUnrotatedBytes = ByteBuffer.allocateDirect(mWidth * mHeight * 4);
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // TODO: This could be optimized by including the rotation in the color conversion.
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            convertImage(mDecodedBuffer, mUnrotatedBytes, mColorFormat, mWidth, mHeight);
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            copyRotate(mUnrotatedBytes, outBytes, rotation);
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outputVideoFrame.unlock();
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Copy the input data to the output data applying the specified rotation.
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param input The input image data
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param output Buffer for the output image data
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param rotation The rotation to apply
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void copyRotate(ByteBuffer input, ByteBuffer output, int rotation) {
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int offset;
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int pixStride;
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int rowStride;
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch (rotation) {
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case MediaDecoder.ROTATE_NONE:
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                offset = 0;
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pixStride = 1;
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                rowStride = mWidth;
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case MediaDecoder.ROTATE_90_LEFT:
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                offset = (mWidth - 1) * mHeight;
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pixStride = -mHeight;
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                rowStride = 1;
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case MediaDecoder.ROTATE_90_RIGHT:
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                offset = mHeight - 1;
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pixStride = mHeight;
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                rowStride = -1;
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case MediaDecoder.ROTATE_180:
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                offset = mWidth * mHeight - 1;
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pixStride = -1;
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                rowStride = -mWidth;
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unsupported rotation " + rotation + "!");
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PixelUtils.copyPixels(input, output, mWidth, mHeight, offset, pixStride, rowStride);
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Looks for a codec with the specified requirements.
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The set of codecs will be filtered down to those that meet the following requirements:
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * <ol>
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *   <li>The codec is a decoder.</li>
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *   <li>The codec can decode a video of the specified format.</li>
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *   <li>The codec can decode to one of the specified color formats.</li>
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * </ol>
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * If multiple codecs are found, the one with the preferred color-format is taken. Color format
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * preference is determined by the order of their appearance in the color format array.
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param format The format the codec must decode.
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param requiredColorFormats Array of target color spaces ordered by preference.
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return A codec that meets the requirements, or null if no such codec was found.
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static MediaCodec findDecoderCodec(MediaFormat format, int[] requiredColorFormats) {
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        TreeMap<Integer, String> candidateCodecs = new TreeMap<Integer, String>();
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        SparseIntArray colorPriorities = intArrayToPriorityMap(requiredColorFormats);
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Get next codec
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Check that this is a decoder
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (info.isEncoder()) {
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                continue;
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Check if this codec can decode the video in question
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String requiredType = format.getString(MediaFormat.KEY_MIME);
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String[] supportedTypes = info.getSupportedTypes();
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Set<String> typeSet = new HashSet<String>(Arrays.asList(supportedTypes));
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Check if it can decode to one of the required color formats
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (typeSet.contains(requiredType)) {
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                CodecCapabilities capabilities = info.getCapabilitiesForType(requiredType);
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                for (int supportedColorFormat : capabilities.colorFormats) {
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    if (colorPriorities.indexOfKey(supportedColorFormat) >= 0) {
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        int priority = colorPriorities.get(supportedColorFormat);
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        candidateCodecs.put(priority, info.getName());
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Pick the best codec (with the highest color priority)
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (candidateCodecs.isEmpty()) {
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return null;
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String bestCodec = candidateCodecs.firstEntry().getValue();
21883511d2f49c9e272f328730586c3d0a7852247f2Andy Hung            try {
21983511d2f49c9e272f328730586c3d0a7852247f2Andy Hung                return MediaCodec.createByCodecName(bestCodec);
22083511d2f49c9e272f328730586c3d0a7852247f2Andy Hung            } catch (IOException e) {
22183511d2f49c9e272f328730586c3d0a7852247f2Andy Hung                throw new RuntimeException(
22283511d2f49c9e272f328730586c3d0a7852247f2Andy Hung                        "failed to create codec for "
22383511d2f49c9e272f328730586c3d0a7852247f2Andy Hung                        + bestCodec, e);
22483511d2f49c9e272f328730586c3d0a7852247f2Andy Hung            }
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static SparseIntArray intArrayToPriorityMap(int[] values) {
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        SparseIntArray result = new SparseIntArray();
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int priority = 0; priority < values.length; ++priority) {
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            result.append(values[priority], priority);
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static void convertImage(
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ByteBuffer input, ByteBuffer output, int colorFormat, int width, int height) {
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch (colorFormat) {
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case CodecCapabilities.COLOR_Format32bitARGB8888:
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                ColorSpace.convertArgb8888ToRgba8888(input, output, width, height);
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case CodecCapabilities.COLOR_FormatYUV420Planar:
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                ColorSpace.convertYuv420pToRgba8888(input, output, width, height);
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Unsupported color format: " + colorFormat + "!");
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
251