blob: 0219fd787f810a70eeb0b656407bc4e078f12889 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media.filterfw.decoder;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaFormat;
import androidx.media.filterfw.FrameValue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* {@link TrackDecoder} for decoding audio tracks.
*
* TODO: find out if we always get 16 bits per channel and document.
*/
@TargetApi(16)
public class AudioTrackDecoder extends TrackDecoder {
private final ByteArrayOutputStream mAudioByteStream; // Guarded by mAudioByteStreamLock.
private final Object mAudioByteStreamLock;
private int mAudioSampleRate;
private int mAudioChannelCount;
private long mAudioPresentationTimeUs;
public AudioTrackDecoder(int trackIndex, MediaFormat format, Listener listener) {
super(trackIndex, format, listener);
if (!DecoderUtil.isAudioFormat(format)) {
throw new IllegalArgumentException(
"AudioTrackDecoder can only be used with audio formats");
}
mAudioByteStream = new ByteArrayOutputStream();
mAudioByteStreamLock = new Object();
mAudioSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
mAudioChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
}
@Override
protected MediaCodec initMediaCodec(MediaFormat format) {
MediaCodec mediaCodec = MediaCodec.createDecoderByType(
format.getString(MediaFormat.KEY_MIME));
mediaCodec.configure(format, null, null, 0);
return mediaCodec;
}
@Override
protected boolean onDataAvailable(
MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info) {
ByteBuffer buffer = buffers[bufferIndex];
byte[] data = new byte[info.size];
buffer.position(info.offset);
buffer.get(data, 0, info.size);
synchronized (mAudioByteStreamLock) {
try {
if (mAudioByteStream.size() == 0 && data.length > 0) {
mAudioPresentationTimeUs = info.presentationTimeUs;
}
mAudioByteStream.write(data);
} catch (IOException e) {
// Just drop the audio sample.
}
}
buffer.clear();
codec.releaseOutputBuffer(bufferIndex, false);
notifyListener();
return true;
}
/**
* Fills the argument {@link FrameValue} with an audio sample containing the audio that was
* decoded since the last call of this method. The decoder's buffer is cleared as a result.
*/
public void grabSample(FrameValue audioFrame) {
synchronized (mAudioByteStreamLock) {
if (audioFrame != null) {
AudioSample sample = new AudioSample(
mAudioSampleRate, mAudioChannelCount, mAudioByteStream.toByteArray());
audioFrame.setValue(sample);
audioFrame.setTimestamp(mAudioPresentationTimeUs * 1000);
}
clearBuffer();
}
}
/**
* Clears the decoder's buffer.
*/
public void clearBuffer() {
synchronized (mAudioByteStreamLock) {
mAudioByteStream.reset();
}
}
}