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