AudioTrackDecoder.java revision 8ca55fc980a567270d397c7392fd5fa8490f6d42
1/* 2 * Copyright (C) 2012 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 17package androidx.media.filterfw.decoder; 18 19import android.annotation.TargetApi; 20import android.media.MediaCodec; 21import android.media.MediaCodec.BufferInfo; 22import android.media.MediaFormat; 23 24import androidx.media.filterfw.FrameValue; 25 26import java.io.ByteArrayOutputStream; 27import java.io.IOException; 28import java.nio.ByteBuffer; 29 30/** 31 * {@link TrackDecoder} for decoding audio tracks. 32 * 33 * TODO: find out if we always get 16 bits per channel and document. 34 */ 35@TargetApi(16) 36public class AudioTrackDecoder extends TrackDecoder { 37 38 private final ByteArrayOutputStream mAudioByteStream; // Guarded by mAudioByteStreamLock. 39 private final Object mAudioByteStreamLock; 40 41 private int mAudioSampleRate; 42 private int mAudioChannelCount; 43 private long mAudioPresentationTimeUs; 44 45 public AudioTrackDecoder(int trackIndex, MediaFormat format, Listener listener) { 46 super(trackIndex, format, listener); 47 48 if (!DecoderUtil.isAudioFormat(format)) { 49 throw new IllegalArgumentException( 50 "AudioTrackDecoder can only be used with audio formats"); 51 } 52 53 mAudioByteStream = new ByteArrayOutputStream(); 54 mAudioByteStreamLock = new Object(); 55 56 mAudioSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 57 mAudioChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 58 } 59 60 @Override 61 protected MediaCodec initMediaCodec(MediaFormat format) { 62 MediaCodec mediaCodec = MediaCodec.createDecoderByType( 63 format.getString(MediaFormat.KEY_MIME)); 64 mediaCodec.configure(format, null, null, 0); 65 return mediaCodec; 66 } 67 68 @Override 69 protected boolean onDataAvailable( 70 MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info) { 71 ByteBuffer buffer = buffers[bufferIndex]; 72 byte[] data = new byte[info.size]; 73 buffer.position(info.offset); 74 buffer.get(data, 0, info.size); 75 76 synchronized (mAudioByteStreamLock) { 77 try { 78 if (mAudioByteStream.size() == 0 && data.length > 0) { 79 mAudioPresentationTimeUs = info.presentationTimeUs; 80 } 81 82 mAudioByteStream.write(data); 83 } catch (IOException e) { 84 // Just drop the audio sample. 85 } 86 } 87 88 buffer.clear(); 89 codec.releaseOutputBuffer(bufferIndex, false); 90 notifyListener(); 91 return true; 92 } 93 94 /** 95 * Fills the argument {@link FrameValue} with an audio sample containing the audio that was 96 * decoded since the last call of this method. The decoder's buffer is cleared as a result. 97 */ 98 public void grabSample(FrameValue audioFrame) { 99 synchronized (mAudioByteStreamLock) { 100 if (audioFrame != null) { 101 AudioSample sample = new AudioSample( 102 mAudioSampleRate, mAudioChannelCount, mAudioByteStream.toByteArray()); 103 audioFrame.setValue(sample); 104 audioFrame.setTimestamp(mAudioPresentationTimeUs * 1000); 105 } 106 clearBuffer(); 107 } 108 } 109 110 /** 111 * Clears the decoder's buffer. 112 */ 113 public void clearBuffer() { 114 synchronized (mAudioByteStreamLock) { 115 mAudioByteStream.reset(); 116 } 117 } 118 119} 120