1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.mediapc.cts; 18 19 import android.media.AudioAttributes; 20 import android.media.AudioFormat; 21 import android.media.AudioTrack; 22 import android.media.MediaCodec; 23 import android.media.MediaExtractor; 24 import android.media.MediaFormat; 25 26 import java.nio.ByteBuffer; 27 28 /** 29 * The following class decode and render the audio (will be audible), until loadStatus is finished. 30 * If input reaches eos, it will rewind the input to start position. 31 */ 32 class AudioPlaybackLoad extends CodecDecoderTestBase { 33 private final String mDecoderName; 34 private final LoadStatus mLoadStatus; 35 36 private long mBasePts; 37 private long mMaxPts; 38 private AudioTrack mTrack; 39 AudioPlaybackLoad(String mediaType, String testFile, String decoderName, LoadStatus loadStatus)40 AudioPlaybackLoad(String mediaType, String testFile, String decoderName, 41 LoadStatus loadStatus) { 42 super(mediaType, testFile); 43 mDecoderName = decoderName; 44 mLoadStatus = loadStatus; 45 mBasePts = 0; 46 mMaxPts = 0; 47 } 48 doDecodeAndPlayback()49 public void doDecodeAndPlayback() throws Exception { 50 MediaFormat format = setUpSource(mTestFile); 51 mTrack = createAudioTrack(format); 52 mTrack.play(); 53 mCodec = MediaCodec.createByCodecName(mDecoderName); 54 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 55 configureCodec(format, false, false, false); 56 mCodec.start(); 57 doWork(Integer.MAX_VALUE); 58 queueEOS(); 59 waitForAllOutputs(); 60 mCodec.stop(); 61 mCodec.release(); 62 mExtractor.release(); 63 mTrack.pause(); 64 mTrack.flush(); 65 mTrack.release(); 66 } 67 createAudioTrack(MediaFormat format)68 private AudioTrack createAudioTrack(MediaFormat format) { 69 final int channelMask = getChannelMask(format); 70 final int encoding = AudioFormat.ENCODING_PCM_16BIT; 71 final int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 72 final AudioFormat audioFormat = new AudioFormat.Builder() 73 .setEncoding(encoding) 74 .setSampleRate(sampleRate) 75 .setChannelMask(channelMask) 76 .build(); 77 final AudioAttributes audioAttributes = new AudioAttributes.Builder() 78 .setUsage(AudioAttributes.USAGE_MEDIA) 79 .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE) 80 .build(); 81 final int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelMask, encoding); 82 final int bufferSize = 2 * minBufferSize; 83 return new AudioTrack.Builder() 84 .setBufferSizeInBytes(bufferSize) 85 .setAudioAttributes(audioAttributes) 86 .setAudioFormat(audioFormat) 87 .build(); 88 } 89 getChannelMask(MediaFormat format)90 private int getChannelMask(MediaFormat format) { 91 final int count = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 92 if (count == 1) { 93 return AudioFormat.CHANNEL_OUT_MONO; 94 } else if (count == 2) { 95 return AudioFormat.CHANNEL_OUT_STEREO; 96 } else if (count == 6) { 97 return AudioFormat.CHANNEL_OUT_5POINT1; 98 } 99 return -1; 100 } 101 102 // Enqueue input to decoder until loadStatus is finished or unexpected eos is seen. 103 @Override enqueueInput(int bufferIndex)104 void enqueueInput(int bufferIndex) { 105 if (mExtractor.getSampleSize() < 0 || mLoadStatus.isLoadFinished()) { 106 enqueueEOS(bufferIndex); 107 } else { 108 ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex); 109 int size = mExtractor.readSampleData(inputBuffer, 0); 110 long pts = mExtractor.getSampleTime(); 111 mMaxPts = Math.max(mMaxPts, mBasePts + pts); 112 int extractorFlags = mExtractor.getSampleFlags(); 113 int codecFlags = 0; 114 if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 115 codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME; 116 } 117 mCodec.queueInputBuffer(bufferIndex, 0, size, mBasePts + pts, codecFlags); 118 if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 119 mInputCount++; 120 } 121 // If eos is reached, seek to start position. 122 if (!mExtractor.advance()) { 123 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 124 mBasePts = mMaxPts + 1000000L; 125 } 126 } 127 } 128 129 @Override releaseOutput(int bufferIndex, MediaCodec.BufferInfo info)130 void releaseOutput(int bufferIndex, MediaCodec.BufferInfo info) { 131 final ByteBuffer buffer = mCodec.getOutputBuffer(bufferIndex); 132 final byte[] audio = new byte[info.size]; 133 buffer.clear(); // prepare buffer for reading 134 buffer.get(audio); 135 mTrack.write(audio, 0, audio.length); 136 mCodec.releaseOutputBuffer(bufferIndex, false); 137 } 138 } 139