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 mime, String testFile, String decoderName, LoadStatus loadStatus)40 AudioPlaybackLoad(String mime, String testFile, String decoderName, LoadStatus loadStatus) { 41 super(mime, testFile); 42 mDecoderName = decoderName; 43 mLoadStatus = loadStatus; 44 mBasePts = 0; 45 mMaxPts = 0; 46 } 47 doDecodeAndPlayback()48 public void doDecodeAndPlayback() throws Exception { 49 MediaFormat format = setUpSource(mTestFile); 50 mTrack = createAudioTrack(format); 51 mTrack.play(); 52 mCodec = MediaCodec.createByCodecName(mDecoderName); 53 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 54 configureCodec(format, false, false, false); 55 mCodec.start(); 56 doWork(Integer.MAX_VALUE); 57 queueEOS(); 58 waitForAllOutputs(); 59 mCodec.stop(); 60 mCodec.release(); 61 mExtractor.release(); 62 mTrack.pause(); 63 mTrack.flush(); 64 mTrack.release(); 65 } 66 createAudioTrack(MediaFormat format)67 private AudioTrack createAudioTrack(MediaFormat format) { 68 final int channelMask = getChannelMask(format); 69 final int encoding = AudioFormat.ENCODING_PCM_16BIT; 70 final int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 71 final AudioFormat audioFormat = new AudioFormat.Builder() 72 .setEncoding(encoding) 73 .setSampleRate(sampleRate) 74 .setChannelMask(channelMask) 75 .build(); 76 final AudioAttributes audioAttributes = new AudioAttributes.Builder() 77 .setUsage(AudioAttributes.USAGE_MEDIA) 78 .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE) 79 .build(); 80 final int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelMask, encoding); 81 final int bufferSize = 2 * minBufferSize; 82 return new AudioTrack.Builder() 83 .setBufferSizeInBytes(bufferSize) 84 .setAudioAttributes(audioAttributes) 85 .setAudioFormat(audioFormat) 86 .build(); 87 } 88 getChannelMask(MediaFormat format)89 private int getChannelMask(MediaFormat format) { 90 final int count = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 91 if (count == 1) { 92 return AudioFormat.CHANNEL_OUT_MONO; 93 } else if (count == 2) { 94 return AudioFormat.CHANNEL_OUT_STEREO; 95 } else if (count == 6) { 96 return AudioFormat.CHANNEL_OUT_5POINT1; 97 } 98 return -1; 99 } 100 101 // Enqueue input to decoder until loadStatus is finished or unexpected eos is seen. 102 @Override enqueueInput(int bufferIndex)103 void enqueueInput(int bufferIndex) { 104 if (mExtractor.getSampleSize() < 0 || mLoadStatus.isLoadFinished()) { 105 enqueueEOS(bufferIndex); 106 } else { 107 ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex); 108 int size = mExtractor.readSampleData(inputBuffer, 0); 109 long pts = mExtractor.getSampleTime(); 110 mMaxPts = Math.max(mMaxPts, mBasePts + pts); 111 int extractorFlags = mExtractor.getSampleFlags(); 112 int codecFlags = 0; 113 if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 114 codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME; 115 } 116 mCodec.queueInputBuffer(bufferIndex, 0, size, mBasePts + pts, codecFlags); 117 if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 118 mInputCount++; 119 } 120 // If eos is reached, seek to start position. 121 if (!mExtractor.advance()) { 122 mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 123 mBasePts = mMaxPts + 1000000L; 124 } 125 } 126 } 127 128 @Override dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)129 void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) { 130 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 131 mSawOutputEOS = true; 132 } 133 if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 134 mOutputCount++; 135 } 136 final ByteBuffer buffer = mCodec.getOutputBuffer(bufferIndex); 137 final byte[] audio = new byte[info.size]; 138 buffer.clear(); // prepare buffer for reading 139 buffer.get(audio); 140 mTrack.write(audio, 0, audio.length); 141 mCodec.releaseOutputBuffer(bufferIndex, false); 142 } 143 } 144